@pencil-agent/nano-pencil 1.14.4 → 1.14.5
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/build-meta.json +3 -3
- package/dist/cli/args.d.ts +11 -1
- package/dist/cli/args.js +130 -0
- package/dist/core/extensions/index.d.ts +1 -1
- package/dist/core/extensions/types.d.ts +7 -2
- package/dist/core/runtime/agent-session.d.ts +5 -2
- package/dist/core/runtime/agent-session.js +39 -7
- package/dist/core/runtime/sdk.d.ts +21 -1
- package/dist/core/runtime/sdk.js +12 -3
- package/dist/extensions/defaults/AGENT.md +3 -3
- package/dist/extensions/defaults/CLAUDE.md +1 -1
- package/dist/extensions/defaults/sal/index.d.ts +2 -2
- package/dist/extensions/defaults/sal/index.js +16 -2
- package/dist/extensions/defaults/sal/sal-runtime.d.ts +3 -1
- package/dist/extensions/defaults/sal/sal-runtime.js +1 -1
- package/dist/extensions/defaults/sal/sal-trace.d.ts +1 -1
- package/dist/extensions/defaults/sal/sal-trace.js +13 -2
- package/dist/main.js +11 -2
- package/dist/modes/acp/acp-mode.d.ts +3 -0
- package/dist/modes/acp/acp-mode.js +40 -1
- package/dist/modes/agent-loop-result-format.d.ts +10 -0
- package/dist/modes/agent-loop-result-format.js +69 -0
- package/dist/modes/interactive/agent-loop-status.d.ts +8 -0
- package/dist/modes/interactive/agent-loop-status.js +41 -0
- package/dist/modes/interactive/interactive-mode.js +12 -21
- package/dist/modes/interactive/slash-command-arguments.d.ts +13 -1
- package/dist/modes/interactive/slash-command-arguments.js +34 -5
- package/dist/modes/print-mode.d.ts +17 -5
- package/dist/modes/print-mode.js +77 -5
- package/dist/modes/rpc/rpc-client.d.ts +5 -1
- package/dist/modes/rpc/rpc-client.js +6 -0
- package/dist/modes/rpc/rpc-mode.d.ts +6 -2
- package/dist/modes/rpc/rpc-mode.js +52 -17
- package/dist/modes/rpc/rpc-types.d.ts +21 -1
- package/dist/node_modules/@pencil-agent/agent-core/agent-loop-continuations.d.ts +17 -0
- package/dist/node_modules/@pencil-agent/agent-core/agent-loop-continuations.js +60 -0
- package/dist/node_modules/@pencil-agent/agent-core/agent-loop-tool-results.d.ts +10 -0
- package/dist/node_modules/@pencil-agent/agent-core/agent-loop-tool-results.js +137 -0
- package/dist/node_modules/@pencil-agent/agent-core/agent-loop-tool-summaries.d.ts +22 -0
- package/dist/node_modules/@pencil-agent/agent-core/agent-loop-tool-summaries.js +64 -0
- package/dist/node_modules/@pencil-agent/agent-core/agent-loop.d.ts +4 -4
- package/dist/node_modules/@pencil-agent/agent-core/agent-loop.js +440 -39
- package/dist/node_modules/@pencil-agent/agent-core/agent-run-result.d.ts +9 -0
- package/dist/node_modules/@pencil-agent/agent-core/agent-run-result.js +32 -0
- package/dist/node_modules/@pencil-agent/agent-core/agent.d.ts +30 -4
- package/dist/node_modules/@pencil-agent/agent-core/agent.js +75 -2
- package/dist/node_modules/@pencil-agent/agent-core/structured-adaptive-agent-loop.d.ts +2 -2
- package/dist/node_modules/@pencil-agent/agent-core/structured-adaptive-agent-loop.js +74 -226
- package/dist/node_modules/@pencil-agent/agent-core/types.d.ts +60 -27
- package/dist/node_modules/@pencil-agent/agent-core/types.js +1 -1
- package/dist/node_modules/@pencil-agent/ai/models.generated.d.ts +34 -17
- package/dist/node_modules/@pencil-agent/ai/models.generated.js +48 -31
- package/dist/node_modules/@pencil-agent/ai/providers/transform-messages.d.ts +3 -3
- package/dist/node_modules/@pencil-agent/ai/providers/transform-messages.js +42 -27
- package/dist/node_modules/@pencil-agent/ai/stream.d.ts +2 -2
- package/dist/node_modules/@pencil-agent/ai/stream.js +70 -14
- package/dist/node_modules/@pencil-agent/ai/utils/event-stream.d.ts +5 -1
- package/dist/node_modules/@pencil-agent/ai/utils/event-stream.js +15 -3
- package/dist/node_modules/@pencil-agent/tui/tui.d.ts +3 -8
- package/dist/node_modules/@pencil-agent/tui/tui.js +33 -70
- package/docs/agent-loop-frameworks.md +26 -3
- package/package.json +1 -1
package/dist/build-meta.json
CHANGED
package/dist/cli/args.d.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* [TO]: Consumed by main.ts, core/model-resolver.ts
|
|
5
5
|
* [HERE]: cli/args.ts - CLI argument parsing and help display
|
|
6
6
|
*/
|
|
7
|
-
import type
|
|
7
|
+
import { type AgentLoopFrameworkInput, type AgentLoopPolicyOptions, type ThinkingLevel } from "@pencil-agent/agent-core";
|
|
8
8
|
import { type ToolName } from "../core/tools/index.js";
|
|
9
9
|
export type Mode = "text" | "json" | "rpc";
|
|
10
10
|
export interface Args {
|
|
@@ -29,6 +29,16 @@ export interface Args {
|
|
|
29
29
|
extensions?: string[];
|
|
30
30
|
noExtensions?: boolean;
|
|
31
31
|
print?: boolean;
|
|
32
|
+
/** In text print mode, emit the final agent loop result as stderr JSON. */
|
|
33
|
+
printLoopResult?: boolean;
|
|
34
|
+
/** In print mode, exit non-zero when the final agent result is an error. */
|
|
35
|
+
failOnAgentError?: boolean;
|
|
36
|
+
/** In print mode, exit non-zero when any tool permission denial occurred. */
|
|
37
|
+
failOnToolDenial?: boolean;
|
|
38
|
+
/** Non-persistent agent loop framework override for this process/session. */
|
|
39
|
+
agentLoopFramework?: AgentLoopFrameworkInput;
|
|
40
|
+
/** Non-persistent loop policy overrides for this process/session. */
|
|
41
|
+
loopPolicy?: Pick<AgentLoopPolicyOptions, "maxTurnsPerPrompt" | "maxToolCallsPerPrompt" | "maxToolConcurrency" | "maxToolResultBatchSizeChars" | "outputTokenBudget" | "maxOutputTokenRecoveryAttempts" | "maxModelErrorRecoveryAttempts" | "maxStopHookContinuations">;
|
|
32
42
|
export?: string;
|
|
33
43
|
noSkills?: boolean;
|
|
34
44
|
skills?: string[];
|
package/dist/cli/args.js
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* [WHO]: Args, Mode, parseArgs(), printHelp()
|
|
3
|
+
* [FROM]: Depends on agent-core, chalk, config.ts, core/tools
|
|
4
|
+
* [TO]: Consumed by main.ts, core/model-resolver.ts
|
|
5
|
+
* [HERE]: cli/args.ts - CLI argument parsing and help display
|
|
6
|
+
*/
|
|
7
|
+
import { normalizeAgentLoopFramework, } from "@pencil-agent/agent-core";
|
|
1
8
|
import chalk from "chalk";
|
|
2
9
|
import { APP_NAME, CONFIG_DIR_NAME, ENV_AGENT_DIR } from "../config.js";
|
|
3
10
|
import { allTools } from "../core/tools/index.js";
|
|
@@ -5,12 +12,45 @@ const VALID_THINKING_LEVELS = ["off", "minimal", "low", "medium", "high", "xhigh
|
|
|
5
12
|
export function isValidThinkingLevel(level) {
|
|
6
13
|
return VALID_THINKING_LEVELS.includes(level);
|
|
7
14
|
}
|
|
15
|
+
function parseAgentLoopFramework(value) {
|
|
16
|
+
const normalized = normalizeAgentLoopFramework(value);
|
|
17
|
+
if (normalized === "standard" || normalized === "weak-model-compatible") {
|
|
18
|
+
return normalized;
|
|
19
|
+
}
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
function parsePositiveIntegerOption(flag, value) {
|
|
23
|
+
const parsed = Number(value);
|
|
24
|
+
if (Number.isInteger(parsed) && parsed > 0)
|
|
25
|
+
return parsed;
|
|
26
|
+
console.error(chalk.yellow(`Warning: Invalid ${flag} value "${value}". Expected a positive integer.`));
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
function parseNonNegativeIntegerOption(flag, value) {
|
|
30
|
+
const parsed = Number(value);
|
|
31
|
+
if (Number.isInteger(parsed) && parsed >= 0)
|
|
32
|
+
return parsed;
|
|
33
|
+
console.error(chalk.yellow(`Warning: Invalid ${flag} value "${value}". Expected a non-negative integer.`));
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
function parseUnitIntervalOption(flag, value) {
|
|
37
|
+
const parsed = Number(value);
|
|
38
|
+
if (Number.isFinite(parsed) && parsed > 0 && parsed <= 1)
|
|
39
|
+
return parsed;
|
|
40
|
+
console.error(chalk.yellow(`Warning: Invalid ${flag} value "${value}". Expected a number in (0, 1].`));
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
function setLoopPolicyOption(result, key, value) {
|
|
44
|
+
result.loopPolicy = result.loopPolicy ?? {};
|
|
45
|
+
result.loopPolicy[key] = value;
|
|
46
|
+
}
|
|
8
47
|
export function parseArgs(args, extensionFlags) {
|
|
9
48
|
const result = {
|
|
10
49
|
messages: [],
|
|
11
50
|
fileArgs: [],
|
|
12
51
|
unknownFlags: new Map(),
|
|
13
52
|
};
|
|
53
|
+
const outputTokenBudget = {};
|
|
14
54
|
for (let i = 0; i < args.length; i++) {
|
|
15
55
|
const arg = args[i];
|
|
16
56
|
if (arg === "--help" || arg === "-h") {
|
|
@@ -89,6 +129,75 @@ export function parseArgs(args, extensionFlags) {
|
|
|
89
129
|
else if (arg === "--print" || arg === "-p") {
|
|
90
130
|
result.print = true;
|
|
91
131
|
}
|
|
132
|
+
else if (arg === "--print-loop-result") {
|
|
133
|
+
result.printLoopResult = true;
|
|
134
|
+
}
|
|
135
|
+
else if (arg === "--fail-on-agent-error") {
|
|
136
|
+
result.failOnAgentError = true;
|
|
137
|
+
}
|
|
138
|
+
else if (arg === "--fail-on-tool-denial") {
|
|
139
|
+
result.failOnToolDenial = true;
|
|
140
|
+
}
|
|
141
|
+
else if (arg === "--agent-loop" && i + 1 < args.length) {
|
|
142
|
+
const framework = args[++i];
|
|
143
|
+
const normalized = parseAgentLoopFramework(framework);
|
|
144
|
+
if (normalized) {
|
|
145
|
+
result.agentLoopFramework = normalized;
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
console.error(chalk.yellow(`Warning: Invalid agent loop framework "${framework}". Valid values: standard, weak-model-compatible.`));
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
else if (arg === "--max-turns-per-prompt" && i + 1 < args.length) {
|
|
152
|
+
const value = parsePositiveIntegerOption(arg, args[++i]);
|
|
153
|
+
if (value !== undefined)
|
|
154
|
+
setLoopPolicyOption(result, "maxTurnsPerPrompt", value);
|
|
155
|
+
}
|
|
156
|
+
else if (arg === "--max-tool-calls-per-prompt" && i + 1 < args.length) {
|
|
157
|
+
const value = parsePositiveIntegerOption(arg, args[++i]);
|
|
158
|
+
if (value !== undefined)
|
|
159
|
+
setLoopPolicyOption(result, "maxToolCallsPerPrompt", value);
|
|
160
|
+
}
|
|
161
|
+
else if (arg === "--max-tool-concurrency" && i + 1 < args.length) {
|
|
162
|
+
const value = parsePositiveIntegerOption(arg, args[++i]);
|
|
163
|
+
if (value !== undefined)
|
|
164
|
+
setLoopPolicyOption(result, "maxToolConcurrency", value);
|
|
165
|
+
}
|
|
166
|
+
else if (arg === "--max-tool-result-batch-size-chars" && i + 1 < args.length) {
|
|
167
|
+
const value = parsePositiveIntegerOption(arg, args[++i]);
|
|
168
|
+
if (value !== undefined)
|
|
169
|
+
setLoopPolicyOption(result, "maxToolResultBatchSizeChars", value);
|
|
170
|
+
}
|
|
171
|
+
else if (arg === "--output-token-budget" && i + 1 < args.length) {
|
|
172
|
+
const value = parsePositiveIntegerOption(arg, args[++i]);
|
|
173
|
+
if (value !== undefined)
|
|
174
|
+
outputTokenBudget.targetTokens = value;
|
|
175
|
+
}
|
|
176
|
+
else if (arg === "--output-token-budget-threshold" && i + 1 < args.length) {
|
|
177
|
+
const value = parseUnitIntervalOption(arg, args[++i]);
|
|
178
|
+
if (value !== undefined)
|
|
179
|
+
outputTokenBudget.thresholdPct = value;
|
|
180
|
+
}
|
|
181
|
+
else if (arg === "--output-token-budget-continuations" && i + 1 < args.length) {
|
|
182
|
+
const value = parseNonNegativeIntegerOption(arg, args[++i]);
|
|
183
|
+
if (value !== undefined)
|
|
184
|
+
outputTokenBudget.maxContinuations = value;
|
|
185
|
+
}
|
|
186
|
+
else if (arg === "--max-output-token-recovery-attempts" && i + 1 < args.length) {
|
|
187
|
+
const value = parseNonNegativeIntegerOption(arg, args[++i]);
|
|
188
|
+
if (value !== undefined)
|
|
189
|
+
setLoopPolicyOption(result, "maxOutputTokenRecoveryAttempts", value);
|
|
190
|
+
}
|
|
191
|
+
else if (arg === "--max-model-error-recovery-attempts" && i + 1 < args.length) {
|
|
192
|
+
const value = parseNonNegativeIntegerOption(arg, args[++i]);
|
|
193
|
+
if (value !== undefined)
|
|
194
|
+
setLoopPolicyOption(result, "maxModelErrorRecoveryAttempts", value);
|
|
195
|
+
}
|
|
196
|
+
else if (arg === "--max-stop-hook-continuations" && i + 1 < args.length) {
|
|
197
|
+
const value = parseNonNegativeIntegerOption(arg, args[++i]);
|
|
198
|
+
if (value !== undefined)
|
|
199
|
+
setLoopPolicyOption(result, "maxStopHookContinuations", value);
|
|
200
|
+
}
|
|
92
201
|
else if (arg === "--export" && i + 1 < args.length) {
|
|
93
202
|
result.export = args[++i];
|
|
94
203
|
}
|
|
@@ -168,6 +277,13 @@ export function parseArgs(args, extensionFlags) {
|
|
|
168
277
|
result.messages.push(arg);
|
|
169
278
|
}
|
|
170
279
|
}
|
|
280
|
+
if (outputTokenBudget.targetTokens !== undefined) {
|
|
281
|
+
setLoopPolicyOption(result, "outputTokenBudget", {
|
|
282
|
+
targetTokens: outputTokenBudget.targetTokens,
|
|
283
|
+
thresholdPct: outputTokenBudget.thresholdPct,
|
|
284
|
+
maxContinuations: outputTokenBudget.maxContinuations,
|
|
285
|
+
});
|
|
286
|
+
}
|
|
171
287
|
return result;
|
|
172
288
|
}
|
|
173
289
|
export function printHelp() {
|
|
@@ -194,6 +310,20 @@ ${chalk.bold("Options:")}
|
|
|
194
310
|
--append-system-prompt <text> Append text or file contents to the system prompt
|
|
195
311
|
--mode <mode> Output mode: text (default), json, or rpc
|
|
196
312
|
--print, -p Non-interactive mode: process prompt and exit
|
|
313
|
+
--print-loop-result In text print mode, write final loop result JSON to stderr
|
|
314
|
+
--fail-on-agent-error In print mode, exit non-zero when final loop result is an error
|
|
315
|
+
--fail-on-tool-denial In print mode, exit non-zero when tools were denied
|
|
316
|
+
--agent-loop <framework> Override loop framework: standard or weak-model-compatible
|
|
317
|
+
--max-turns-per-prompt <n> Stop a prompt after n assistant turns
|
|
318
|
+
--max-tool-calls-per-prompt <n> Stop a prompt after n tool calls
|
|
319
|
+
--max-tool-concurrency <n> Max concurrent safe tool calls in compatible loop
|
|
320
|
+
--max-tool-result-batch-size-chars <n> Max aggregate tool result chars per turn
|
|
321
|
+
--output-token-budget <n> Continue when final output is below n tokens
|
|
322
|
+
--output-token-budget-threshold <n> Continuation threshold ratio in (0,1], default loop policy
|
|
323
|
+
--output-token-budget-continuations <n> Max output-budget continuations
|
|
324
|
+
--max-output-token-recovery-attempts <n> Max recovery turns after output-token stops
|
|
325
|
+
--max-model-error-recovery-attempts <n> Max in-loop model error recoveries
|
|
326
|
+
--max-stop-hook-continuations <n> Max stop-hook validation continuations
|
|
197
327
|
--continue, -c Continue previous session
|
|
198
328
|
--resume, -r Select a session to resume
|
|
199
329
|
--session <path> Use specific session file
|
|
@@ -8,6 +8,6 @@ export type { SlashCommandInfo, SlashCommandLocation, SlashCommandSource } from
|
|
|
8
8
|
export { createExtensionRuntime, discoverAndLoadExtensions, loadExtensionFromFactory, loadExtensions, } from "./loader.js";
|
|
9
9
|
export type { ExtensionErrorListener, ForkHandler, NavigateTreeHandler, NewSessionHandler, ShutdownHandler, SwitchSessionHandler, } from "./runner.js";
|
|
10
10
|
export { ExtensionRunner } from "./runner.js";
|
|
11
|
-
export type { AgentEndEvent, AgentStartEvent, AgentToolResult, AgentToolUpdateCallback, AppAction, AppendEntryHandler, BashToolCallEvent, BashToolResultEvent, BeforeAgentStartEvent, BeforeAgentStartEventResult, CompactOptions, ContextEvent, ContextEventResult, ContextUsage, CustomToolCallEvent, CustomToolResultEvent, EditToolCallEvent, EditToolResultEvent, ExecOptions, ExecResult, Extension, ExtensionActions, ExtensionAPI, ExtensionCommandContext, ExtensionCommandContextActions, ExtensionContext, ExtensionContextActions, ExtensionError, ExtensionEvent, ExtensionFactory, ExtensionFlag, ExtensionHandler, ExtensionRuntime, ExtensionShortcut, ExtensionUIContext, ExtensionUIDialogOptions, ExtensionWidgetOptions, FindToolCallEvent, FindToolResultEvent, GetActiveToolsHandler, GetAllToolsHandler, GetCommandsHandler, GetThinkingLevelHandler, GrepToolCallEvent, GrepToolResultEvent, InputEvent, InputEventResult, InputSource, KeybindingsManager, LoadExtensionsResult, LsToolCallEvent, LsToolResultEvent, MessageEndEvent, MessageRenderer, MessageRenderOptions, MessageStartEvent, MessageUpdateEvent, ModelSelectEvent, ModelSelectSource, ProviderConfig, ProviderModelConfig, ReadToolCallEvent, ReadToolResultEvent, RegisteredCommand, RegisteredTool, ResourcesDiscoverEvent, ResourcesDiscoverResult, SendMessageHandler, SendUserMessageHandler, SessionBeforeCompactEvent, SessionBeforeCompactResult, SessionBeforeForkEvent, SessionBeforeForkResult, SessionBeforeSwitchEvent, SessionBeforeSwitchResult, SessionBeforeTreeEvent, SessionBeforeTreeResult, SessionCompactEvent, SessionEvent, SessionForkEvent, SessionShutdownEvent, SessionStartEvent, SessionSwitchEvent, SessionTreeEvent, SetActiveToolsHandler, SetLabelHandler, SetModelHandler, SetThinkingLevelHandler, TerminalInputHandler, ToolCallEvent, ToolCallEventResult, ToolDefinition, ToolExecutionEndEvent, ToolExecutionStartEvent, ToolExecutionUpdateEvent, ToolInfo, ToolRenderResultOptions, ToolResultEvent, ToolResultEventResult, TreePreparation, TurnEndEvent, TurnStartEvent, UserBashEvent, UserBashEventResult, WidgetPlacement, WriteToolCallEvent, WriteToolResultEvent, } from "./types.js";
|
|
11
|
+
export type { AgentEndEvent, AgentResultEvent, AgentStartEvent, AgentToolResult, AgentToolUpdateCallback, AppAction, AppendEntryHandler, BashToolCallEvent, BashToolResultEvent, BeforeAgentStartEvent, BeforeAgentStartEventResult, CompactOptions, ContextEvent, ContextEventResult, ContextUsage, CustomToolCallEvent, CustomToolResultEvent, EditToolCallEvent, EditToolResultEvent, ExecOptions, ExecResult, Extension, ExtensionActions, ExtensionAPI, ExtensionCommandContext, ExtensionCommandContextActions, ExtensionContext, ExtensionContextActions, ExtensionError, ExtensionEvent, ExtensionFactory, ExtensionFlag, ExtensionHandler, ExtensionRuntime, ExtensionShortcut, ExtensionUIContext, ExtensionUIDialogOptions, ExtensionWidgetOptions, FindToolCallEvent, FindToolResultEvent, GetActiveToolsHandler, GetAllToolsHandler, GetCommandsHandler, GetThinkingLevelHandler, GrepToolCallEvent, GrepToolResultEvent, InputEvent, InputEventResult, InputSource, KeybindingsManager, LoadExtensionsResult, LsToolCallEvent, LsToolResultEvent, MessageEndEvent, MessageRenderer, MessageRenderOptions, MessageStartEvent, MessageUpdateEvent, ModelSelectEvent, ModelSelectSource, ProviderConfig, ProviderModelConfig, ReadToolCallEvent, ReadToolResultEvent, RegisteredCommand, RegisteredTool, ResourcesDiscoverEvent, ResourcesDiscoverResult, SendMessageHandler, SendUserMessageHandler, SessionBeforeCompactEvent, SessionBeforeCompactResult, SessionBeforeForkEvent, SessionBeforeForkResult, SessionBeforeSwitchEvent, SessionBeforeSwitchResult, SessionBeforeTreeEvent, SessionBeforeTreeResult, SessionCompactEvent, SessionEvent, SessionForkEvent, SessionShutdownEvent, SessionStartEvent, SessionSwitchEvent, SessionTreeEvent, SetActiveToolsHandler, SetLabelHandler, SetModelHandler, SetThinkingLevelHandler, TerminalInputHandler, ToolCallEvent, ToolCallEventResult, ToolDefinition, ToolExecutionEndEvent, ToolExecutionStartEvent, ToolExecutionUpdateEvent, ToolInfo, ToolRenderResultOptions, ToolResultEvent, ToolResultEventResult, TreePreparation, TurnEndEvent, TurnStartEvent, UserBashEvent, UserBashEventResult, WidgetPlacement, WriteToolCallEvent, WriteToolResultEvent, } from "./types.js";
|
|
12
12
|
export { isBashToolResult, isEditToolResult, isFindToolResult, isGrepToolResult, isLsToolResult, isReadToolResult, isToolCallEventType, isWriteToolResult, } from "./types.js";
|
|
13
13
|
export { wrapRegisteredTool, wrapRegisteredTools, wrapToolsWithExtensions, wrapToolWithExtensions, } from "./wrapper.js";
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* [TO]: Consumed by core/extensions/index.ts, core/extensions/runner.ts, core/extensions/wrapper.ts, all extension entry points (defaults/loop, defaults/team, defaults/mcp, defaults/soul, defaults/presence, defaults/security-audit, defaults/link-world, defaults/interview, optional/simplify, optional/export-html), modes/interactive/components/tool-execution.ts, modes/interactive/components/custom-message.ts, modes/acp/acp-mode.ts
|
|
5
5
|
* [HERE]: core/extensions/types.ts - type definitions for extension system API
|
|
6
6
|
*/
|
|
7
|
-
import type { AgentMessage, AgentToolResult, AgentToolUpdateCallback, AgentLoopFramework, ThinkingLevel } from "@pencil-agent/agent-core";
|
|
7
|
+
import type { AgentMessage, AgentRunResult, AgentToolResult, AgentToolUpdateCallback, AgentLoopFramework, ThinkingLevel } from "@pencil-agent/agent-core";
|
|
8
8
|
import type { Api, AssistantMessageEvent, AssistantMessageEventStream, Context, ImageContent, Model, OAuthCredentials, OAuthLoginCallbacks, SimpleStreamOptions, TextContent, ToolResultMessage, Usage } from "@pencil-agent/ai";
|
|
9
9
|
import type { AutocompleteItem, Component, EditorComponent, EditorTheme, KeyId, OverlayHandle, OverlayOptions, TUI } from "@pencil-agent/tui";
|
|
10
10
|
import type { Static, TSchema } from "@sinclair/typebox";
|
|
@@ -418,6 +418,10 @@ export interface AgentEndEvent {
|
|
|
418
418
|
type: "agent_end";
|
|
419
419
|
messages: AgentMessage[];
|
|
420
420
|
}
|
|
421
|
+
/** Fired with structured loop outcome metadata before agent_end */
|
|
422
|
+
export interface AgentResultEvent extends AgentRunResult {
|
|
423
|
+
type: "agent_result";
|
|
424
|
+
}
|
|
421
425
|
/** Fired at the start of each turn */
|
|
422
426
|
export interface TurnStartEvent {
|
|
423
427
|
type: "turn_start";
|
|
@@ -628,7 +632,7 @@ export declare function isToolCallEventType<TName extends string, TInput extends
|
|
|
628
632
|
input: TInput;
|
|
629
633
|
};
|
|
630
634
|
/** Union of all event types */
|
|
631
|
-
export type ExtensionEvent = ResourcesDiscoverEvent | SessionEvent | ContextEvent | BeforeAgentStartEvent | AgentStartEvent | AgentEndEvent | TurnStartEvent | TurnEndEvent | MessageStartEvent | MessageUpdateEvent | MessageEndEvent | ToolExecutionStartEvent | ToolExecutionUpdateEvent | ToolExecutionEndEvent | ModelSelectEvent | UserBashEvent | InputEvent | ToolCallEvent | ToolResultEvent;
|
|
635
|
+
export type ExtensionEvent = ResourcesDiscoverEvent | SessionEvent | ContextEvent | BeforeAgentStartEvent | AgentStartEvent | AgentEndEvent | AgentResultEvent | TurnStartEvent | TurnEndEvent | MessageStartEvent | MessageUpdateEvent | MessageEndEvent | ToolExecutionStartEvent | ToolExecutionUpdateEvent | ToolExecutionEndEvent | ModelSelectEvent | UserBashEvent | InputEvent | ToolCallEvent | ToolResultEvent;
|
|
632
636
|
export interface ContextEventResult {
|
|
633
637
|
messages?: AgentMessage[];
|
|
634
638
|
}
|
|
@@ -723,6 +727,7 @@ export interface ExtensionAPI {
|
|
|
723
727
|
on(event: "context", handler: ExtensionHandler<ContextEvent, ContextEventResult>): void;
|
|
724
728
|
on(event: "before_agent_start", handler: ExtensionHandler<BeforeAgentStartEvent, BeforeAgentStartEventResult>): void;
|
|
725
729
|
on(event: "agent_start", handler: ExtensionHandler<AgentStartEvent>): void;
|
|
730
|
+
on(event: "agent_result", handler: ExtensionHandler<AgentResultEvent>): void;
|
|
726
731
|
on(event: "agent_end", handler: ExtensionHandler<AgentEndEvent>): void;
|
|
727
732
|
on(event: "turn_start", handler: ExtensionHandler<TurnStartEvent>): void;
|
|
728
733
|
on(event: "turn_end", handler: ExtensionHandler<TurnEndEvent>): void;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { Agent, AgentEvent, AgentLoopFramework, AgentMessage, AgentState, AgentTool, ThinkingLevel } from "@pencil-agent/agent-core";
|
|
2
|
-
import type { ImageContent, Model, TextContent } from "@pencil-agent/ai";
|
|
1
|
+
import type { Agent, AgentEvent, AgentLoopFramework, AgentLoopPolicyOptions, AgentMessage, AgentState, AgentTool, ThinkingLevel } from "@pencil-agent/agent-core";
|
|
2
|
+
import type { AssistantMessage, ImageContent, Model, TextContent } from "@pencil-agent/ai";
|
|
3
3
|
/**
|
|
4
4
|
* Custom error for model cycling with additional context.
|
|
5
5
|
*/
|
|
@@ -37,6 +37,7 @@ export interface ParsedSkillBlock {
|
|
|
37
37
|
* Returns null if the text doesn't contain a skill block.
|
|
38
38
|
*/
|
|
39
39
|
export declare function parseSkillBlock(text: string): ParsedSkillBlock | null;
|
|
40
|
+
export declare function pruneRecoverableErrorTail(messages: AgentMessage[], assistantMessage: AssistantMessage): AgentMessage[];
|
|
40
41
|
/** Session-specific events that extend the core AgentEvent */
|
|
41
42
|
export type AgentSessionEvent = AgentEvent | {
|
|
42
43
|
type: "auto_compaction_start";
|
|
@@ -465,6 +466,8 @@ export declare class AgentSession {
|
|
|
465
466
|
setThinkingLevel(level: ThinkingLevel): void;
|
|
466
467
|
/** Set the session-level agent loop framework override. */
|
|
467
468
|
setAgentLoopFramework(framework: AgentLoopFrameworkInput | undefined): void;
|
|
469
|
+
/** Update runtime loop policy options for subsequent turns. */
|
|
470
|
+
setLoopPolicy(options: Partial<AgentLoopPolicyOptions>): void;
|
|
468
471
|
/**
|
|
469
472
|
* Cycle to next thinking level.
|
|
470
473
|
* @returns New level, or undefined if model doesn't support thinking
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* [WHO]: AgentSession class, session lifecycle, event emission, in-loop
|
|
2
|
+
* [WHO]: AgentSession class, session lifecycle, event emission, in-loop recovery adapter, pruneRecoverableErrorTail()
|
|
3
3
|
* [FROM]: Depends on agent-core, ai, core/tools/*, core/session/*, core/config/*
|
|
4
4
|
* [TO]: Consumed by core/index.ts, core/runtime/sdk.ts, modes/interactive/interactive-mode.ts, modes/print-mode.ts, modes/rpc/rpc-mode.ts, modes/acp/acp-mode.ts, modes/rpc/rpc-types.ts, modes/rpc/rpc-client.ts, modes/interactive/components/footer.ts, modes/interactive/components/skill-invocation-message.ts
|
|
5
5
|
* [HERE]: Central runtime hub; all modes delegate to this class
|
|
@@ -58,6 +58,34 @@ export function parseSkillBlock(text) {
|
|
|
58
58
|
userMessage: match[4]?.trim() || undefined,
|
|
59
59
|
};
|
|
60
60
|
}
|
|
61
|
+
export function pruneRecoverableErrorTail(messages, assistantMessage) {
|
|
62
|
+
const interruptedToolCallIds = new Set(assistantMessage.content
|
|
63
|
+
.filter((part) => part.type === "toolCall")
|
|
64
|
+
.map((part) => part.id));
|
|
65
|
+
let end = messages.length;
|
|
66
|
+
while (end > 0 &&
|
|
67
|
+
isRecoverableTailToolResult(messages[end - 1], interruptedToolCallIds)) {
|
|
68
|
+
end--;
|
|
69
|
+
}
|
|
70
|
+
if (end > 0 &&
|
|
71
|
+
isSameRecoverableAssistantMessage(messages[end - 1], assistantMessage)) {
|
|
72
|
+
end--;
|
|
73
|
+
}
|
|
74
|
+
return messages.slice(0, end);
|
|
75
|
+
}
|
|
76
|
+
function isRecoverableTailToolResult(message, interruptedToolCallIds) {
|
|
77
|
+
return (message.role === "toolResult" &&
|
|
78
|
+
interruptedToolCallIds.has(message.toolCallId));
|
|
79
|
+
}
|
|
80
|
+
function isSameRecoverableAssistantMessage(message, assistantMessage) {
|
|
81
|
+
return (message.role === "assistant" &&
|
|
82
|
+
message.stopReason === assistantMessage.stopReason &&
|
|
83
|
+
message.timestamp === assistantMessage.timestamp &&
|
|
84
|
+
message.provider === assistantMessage.provider &&
|
|
85
|
+
message.model === assistantMessage.model &&
|
|
86
|
+
message.api === assistantMessage.api &&
|
|
87
|
+
message.errorMessage === assistantMessage.errorMessage);
|
|
88
|
+
}
|
|
61
89
|
// ============================================================================
|
|
62
90
|
// Constants
|
|
63
91
|
// ============================================================================
|
|
@@ -432,6 +460,10 @@ export class AgentSession {
|
|
|
432
460
|
this._turnIndex = 0;
|
|
433
461
|
await this._extensionRunner.emit({ type: "agent_start" });
|
|
434
462
|
}
|
|
463
|
+
else if (event.type === "agent_result") {
|
|
464
|
+
const extensionEvent = { ...event };
|
|
465
|
+
await this._extensionRunner.emit(extensionEvent);
|
|
466
|
+
}
|
|
435
467
|
else if (event.type === "turn_start") {
|
|
436
468
|
const extensionEvent = {
|
|
437
469
|
type: "turn_start",
|
|
@@ -1334,6 +1366,10 @@ export class AgentSession {
|
|
|
1334
1366
|
setAgentLoopFramework(framework) {
|
|
1335
1367
|
this.agent.setAgentLoopFramework(framework);
|
|
1336
1368
|
}
|
|
1369
|
+
/** Update runtime loop policy options for subsequent turns. */
|
|
1370
|
+
setLoopPolicy(options) {
|
|
1371
|
+
this.agent.setLoopPolicy(options);
|
|
1372
|
+
}
|
|
1337
1373
|
/**
|
|
1338
1374
|
* Cycle to next thinking level.
|
|
1339
1375
|
* @returns New level, or undefined if model doesn't support thinking
|
|
@@ -1589,8 +1625,7 @@ export class AgentSession {
|
|
|
1589
1625
|
const shouldRetry = await this._retryCoordinator.handleErrorInLoop(assistantMessage);
|
|
1590
1626
|
if (!shouldRetry)
|
|
1591
1627
|
return { action: "stop" };
|
|
1592
|
-
const
|
|
1593
|
-
const retryMessages = messages.at(-1)?.role === "assistant" ? messages.slice(0, -1) : messages;
|
|
1628
|
+
const retryMessages = pruneRecoverableErrorTail(this.agent.state.messages, assistantMessage);
|
|
1594
1629
|
this.agent.replaceMessages(retryMessages);
|
|
1595
1630
|
return {
|
|
1596
1631
|
action: "retry",
|
|
@@ -1617,10 +1652,7 @@ export class AgentSession {
|
|
|
1617
1652
|
if (errorIsFromBeforeCompaction)
|
|
1618
1653
|
return { action: "stop" };
|
|
1619
1654
|
const messages = this.agent.state.messages;
|
|
1620
|
-
|
|
1621
|
-
messages[messages.length - 1].role === "assistant") {
|
|
1622
|
-
this.agent.replaceMessages(messages.slice(0, -1));
|
|
1623
|
-
}
|
|
1655
|
+
this.agent.replaceMessages(pruneRecoverableErrorTail(messages, assistantMessage));
|
|
1624
1656
|
const recoveredMessages = await this._runAutoCompaction("overflow", true, {
|
|
1625
1657
|
triggerContinue: false,
|
|
1626
1658
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ThinkingLevel } from "@pencil-agent/agent-core";
|
|
1
|
+
import { type AgentLoopFrameworkInput, type AgentLoopPolicyOptions, type ThinkingLevel } from "@pencil-agent/agent-core";
|
|
2
2
|
import type { Model } from "@pencil-agent/ai";
|
|
3
3
|
import { AgentSession } from "./agent-session.js";
|
|
4
4
|
import { AuthStorage } from "../config/auth-storage.js";
|
|
@@ -41,6 +41,26 @@ export interface CreateAgentSessionOptions {
|
|
|
41
41
|
model?: Model<any>;
|
|
42
42
|
/** Thinking level. Default: from settings, else 'medium' (clamped to model capabilities) */
|
|
43
43
|
thinkingLevel?: ThinkingLevel;
|
|
44
|
+
/** Session-level agent loop framework override. Default: from settings/model. */
|
|
45
|
+
agentLoopFramework?: AgentLoopFrameworkInput;
|
|
46
|
+
/** Optional runtime loop policy overrides applied at session creation. */
|
|
47
|
+
loopPolicy?: Pick<AgentLoopPolicyOptions, "maxTurnsPerPrompt" | "maxToolCallsPerPrompt" | "maxToolConcurrency" | "maxToolResultBatchSizeChars" | "outputTokenBudget" | "maxOutputTokenRecoveryAttempts" | "maxModelErrorRecoveryAttempts" | "maxStopHookContinuations">;
|
|
48
|
+
/** Maximum assistant turns allowed for one prompt. */
|
|
49
|
+
maxTurnsPerPrompt?: number;
|
|
50
|
+
/** Maximum tool calls allowed for one prompt. */
|
|
51
|
+
maxToolCallsPerPrompt?: number;
|
|
52
|
+
/** Maximum concurrent safe tool calls in compatible loops. */
|
|
53
|
+
maxToolConcurrency?: number;
|
|
54
|
+
/** Aggregate tool-result batch budget in characters. */
|
|
55
|
+
maxToolResultBatchSizeChars?: number;
|
|
56
|
+
/** Optional target for automatic continuation when output is under-complete. */
|
|
57
|
+
outputTokenBudget?: AgentLoopPolicyOptions["outputTokenBudget"];
|
|
58
|
+
/** Maximum automatic output-token recovery turns per prompt. */
|
|
59
|
+
maxOutputTokenRecoveryAttempts?: number;
|
|
60
|
+
/** Maximum in-loop model error recoveries per prompt. */
|
|
61
|
+
maxModelErrorRecoveryAttempts?: number;
|
|
62
|
+
/** Maximum stop-hook validation/correction continuations per prompt. */
|
|
63
|
+
maxStopHookContinuations?: number;
|
|
44
64
|
/** Models available for cycling (Ctrl+P in interactive mode) */
|
|
45
65
|
scopedModels?: Array<{
|
|
46
66
|
model: Model<any>;
|
package/dist/core/runtime/sdk.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* [WHO]: createAgentSession(options) → AgentSession + load results,
|
|
2
|
+
* [WHO]: createAgentSession(options) → AgentSession + load results, loop framework/policy override wiring
|
|
3
3
|
* [FROM]: Depends on agent-core, ai, core/config/*, core/tools/*, core/session/*, core/mcp-*, i18n/*
|
|
4
4
|
* [TO]: Consumed by index.ts, main.ts, test/presence-opening.test.ts, extensions/defaults/team/index.ts
|
|
5
5
|
* [HERE]: SDK factory; creates all services with DI, wires up extensions
|
|
@@ -247,10 +247,19 @@ export async function createAgentSession(options = {}) {
|
|
|
247
247
|
steeringMode: settingsManager.getSteeringMode(),
|
|
248
248
|
followUpMode: settingsManager.getFollowUpMode(),
|
|
249
249
|
transport: settingsManager.getTransport(),
|
|
250
|
-
agentLoopFramework: settingsManager.getAgentLoopFramework(),
|
|
250
|
+
agentLoopFramework: options.agentLoopFramework ?? settingsManager.getAgentLoopFramework(),
|
|
251
251
|
thinkingBudgets: settingsManager.getThinkingBudgets(),
|
|
252
252
|
maxRetryDelayMs: settingsManager.getRetrySettings().maxDelayMs,
|
|
253
|
-
maxToolResultBatchSizeChars:
|
|
253
|
+
maxToolResultBatchSizeChars: options.maxToolResultBatchSizeChars ??
|
|
254
|
+
options.loopPolicy?.maxToolResultBatchSizeChars ??
|
|
255
|
+
settingsManager.getAgentLoopSettings().maxToolResultBatchSizeChars,
|
|
256
|
+
maxToolConcurrency: options.maxToolConcurrency ?? options.loopPolicy?.maxToolConcurrency,
|
|
257
|
+
maxTurnsPerPrompt: options.maxTurnsPerPrompt ?? options.loopPolicy?.maxTurnsPerPrompt,
|
|
258
|
+
maxToolCallsPerPrompt: options.maxToolCallsPerPrompt ?? options.loopPolicy?.maxToolCallsPerPrompt,
|
|
259
|
+
outputTokenBudget: options.outputTokenBudget ?? options.loopPolicy?.outputTokenBudget,
|
|
260
|
+
maxOutputTokenRecoveryAttempts: options.maxOutputTokenRecoveryAttempts ?? options.loopPolicy?.maxOutputTokenRecoveryAttempts,
|
|
261
|
+
maxModelErrorRecoveryAttempts: options.maxModelErrorRecoveryAttempts ?? options.loopPolicy?.maxModelErrorRecoveryAttempts,
|
|
262
|
+
maxStopHookContinuations: options.maxStopHookContinuations ?? options.loopPolicy?.maxStopHookContinuations,
|
|
254
263
|
getApiKey: async (provider) => {
|
|
255
264
|
// Use the provider argument from the in-flight request;
|
|
256
265
|
// agent.state.model may already be switched mid-turn.
|
|
@@ -68,11 +68,11 @@ loop/scheduler-controller.ts: SchedulerController - in-memory recurring task sto
|
|
|
68
68
|
loop/scheduler-parser.ts: Loop command parsing with flags/subcommands, parseSchedulerCommand/parseDurationSpec/buildSchedulerHelp, --name/--max/--quiet
|
|
69
69
|
loop/scheduler-types.ts: Scheduled loop types, LoopPayloadKind/ScheduledLoopTask/LoopStartSpec/ParsedSchedulerCommand
|
|
70
70
|
loop/README.md: Loop extension documentation - recurring scheduler usage and flags
|
|
71
|
-
sal/index.ts: SAL extension entry, enabled by default, registers flags, /sal:* commands, lifecycle hooks, terrain snapshot refresh, eval event emission, and stale-run cleanup scheduling; delegates config, context, runtime contracts, and tool_trace analytics to focused SAL modules
|
|
71
|
+
sal/index.ts: SAL extension entry, enabled by default, registers flags, /sal:* commands, lifecycle hooks including agent_result, terrain snapshot refresh, eval event emission, and stale-run cleanup scheduling; delegates config, context, runtime contracts, and tool_trace analytics to focused SAL modules
|
|
72
72
|
sal/sal-config.ts: SAL build metadata, eval environment constants, credential loading, truthy parsing, stale-cleanup/A-B flag resolution, experiment id normalization, and sidecar directory resolution
|
|
73
73
|
sal/sal-context.ts: SAL anchor system-prompt injection formatting plus A/B sidecar turn-record persistence
|
|
74
|
-
sal/sal-runtime.ts: SAL shared BuildMeta/TurnState/SalRuntime contracts used across config, context, trace, and entry modules
|
|
75
|
-
sal/sal-trace.ts: SAL tool path extraction, task intent inference, and bounded tool_trace payload construction
|
|
74
|
+
sal/sal-runtime.ts: SAL shared BuildMeta/TurnState/SalRuntime contracts used across config, context, trace, and entry modules, including per-turn loop outcome state
|
|
75
|
+
sal/sal-trace.ts: SAL tool path extraction, task intent inference, and bounded tool_trace payload construction with loop outcome summary
|
|
76
76
|
sal/terrain.ts: TerrainSnapshot/TerrainNode/TerrainEdge model, buildTerrainIndex(), checkDipCoverage(), isSnapshotStale(), moduleIdForPath(), parses P2 AGENT.md and P3 file headers
|
|
77
77
|
sal/anchors.ts: StructuralAnchor/AnchorResolution model, locateTask(), locateAction(), evidence-driven scoring with tunable SalWeights, CJK bigram tokenization
|
|
78
78
|
sal/weights.ts: SalWeights interface, SAL_DEFAULT_WEIGHTS, loadSalWeights() reads sal-config.json from workspace or .memory-experiments/sal/
|
|
@@ -49,7 +49,7 @@ plan/exit-plan-mode-tool.ts: createExitPlanModeTool() - ExitPlanMode tool with p
|
|
|
49
49
|
plan/plan-agents.ts: Explore/Plan subagent definitions with read-only tools for plan mode workflow
|
|
50
50
|
plan/plan-validation.ts: validatePlan() - validates plan has required sections (Context, Approach, Files, Verification)
|
|
51
51
|
plan/teammate-approval.ts: isInTeammateContext(), submitPlanToLeader(), formatPlanSubmittedMessage() - teammate plan approval integration
|
|
52
|
-
sal/index.ts: SAL extension entry, enabled by default, registers --nosal/--sal-rebuild-terrain flags, /sal:coverage /sal:status /sal:setup commands, before_agent_start/tool_execution_start/tool_execution_end/agent_end hooks; /sal:setup writes ~/.memory-experiments/credentials.json with adapter inference (insforge/jsonl/noop); publishes structuralAnchor via core/runtime/turn-context (no SAL-specific globals); emits run_start/turn_anchor/memory_recalls/tool_trace/run_end eval events through pluggable EvalSink; reads memoryRecallSnapshot from turn-context bus in agent_end; runtime no-op when --nosal is set; auto-injects pencil_version from build-meta.json into run_start; emergency flush on beforeExit/SIGHUP/SIGTERM; stale run cleanup is opt-in via NANOPENCIL_EVAL_CLEANUP_STALE_RUNS / credentials cleanup_stale_runs; tool_trace is a bounded per-turn summary and includes no-tool turns
|
|
52
|
+
sal/index.ts: SAL extension entry, enabled by default, registers --nosal/--sal-rebuild-terrain flags, /sal:coverage /sal:status /sal:setup commands, before_agent_start/tool_execution_start/tool_execution_end/agent_result/agent_end hooks; /sal:setup writes ~/.memory-experiments/credentials.json with adapter inference (insforge/jsonl/noop); publishes structuralAnchor via core/runtime/turn-context (no SAL-specific globals); emits run_start/turn_anchor/memory_recalls/tool_trace/run_end eval events through pluggable EvalSink; reads memoryRecallSnapshot from turn-context bus in agent_end; runtime no-op when --nosal is set; auto-injects pencil_version from build-meta.json into run_start; emergency flush on beforeExit/SIGHUP/SIGTERM; stale run cleanup is opt-in via NANOPENCIL_EVAL_CLEANUP_STALE_RUNS / credentials cleanup_stale_runs; tool_trace is a bounded per-turn summary and includes no-tool turns plus loop outcome
|
|
53
53
|
sal/terrain.ts: TerrainSnapshot/TerrainNode/TerrainEdge model, async buildTerrainIndex()/isSnapshotStale() (fs/promises + periodic yields so TUI can flush under block terminals like Warp), checkDipCoverage(), moduleIdForPath(), parses P2 CLAUDE.md and P3 file headers
|
|
54
54
|
sal/anchors.ts: StructuralAnchor/AnchorResolution model, locateTask(), locateAction(), evidence-driven scoring with tunable SalWeights, CJK bigram tokenization
|
|
55
55
|
sal/weights.ts: SalWeights interface, SAL_DEFAULT_WEIGHTS, loadSalWeights() reads sal-config.json from workspace or .memory-experiments/sal/
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* [WHO]: SAL extension entry - enabled by default, registers --nosal/--sal-ab/--sal-rebuild-terrain flags, /sal:coverage /sal:status /sal:setup commands, before_agent_start/tool_execution_start/tool_execution_end/agent_end hooks; runtime no-op when --nosal is set
|
|
2
|
+
* [WHO]: SAL extension entry - enabled by default, registers --nosal/--sal-ab/--sal-rebuild-terrain flags, /sal:coverage /sal:status /sal:setup commands, before_agent_start/tool_execution_start/tool_execution_end/agent_result/agent_end hooks; runtime no-op when --nosal is set
|
|
3
3
|
* [FROM]: Depends on core/extensions/types.ts (ToolExecutionStartEvent, ToolExecutionEndEvent), core/runtime/turn-context.ts (publishes structuralAnchor), extensions/defaults/sal/terrain.ts, anchors.ts, weights.ts, eval/index.ts (pluggable adapters)
|
|
4
4
|
* [TO]: Loaded by builtin-extensions.ts as a default extension entry point
|
|
5
|
-
* [HERE]: extensions/defaults/sal/index.ts - pluggable Structural Anchor Localization (SAL) extension; emits run_start/turn_anchor/tool_trace/run_end eval events with best-effort flush/close isolation; tool_trace captures per-turn tool usage
|
|
5
|
+
* [HERE]: extensions/defaults/sal/index.ts - pluggable Structural Anchor Localization (SAL) extension; emits run_start/turn_anchor/tool_trace/run_end eval events with best-effort flush/close isolation; tool_trace captures per-turn tool usage and loop outcome for self-awareness analytics
|
|
6
6
|
*/
|
|
7
7
|
import type { ExtensionAPI } from "../../../core/extensions/types.js";
|
|
8
8
|
import { SAL_DEFAULT_WEIGHTS } from "./weights.js";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* [WHO]: SAL extension entry - enabled by default, registers --nosal/--sal-ab/--sal-rebuild-terrain flags, /sal:coverage /sal:status /sal:setup commands, before_agent_start/tool_execution_start/tool_execution_end/agent_end hooks; runtime no-op when --nosal is set
|
|
2
|
+
* [WHO]: SAL extension entry - enabled by default, registers --nosal/--sal-ab/--sal-rebuild-terrain flags, /sal:coverage /sal:status /sal:setup commands, before_agent_start/tool_execution_start/tool_execution_end/agent_result/agent_end hooks; runtime no-op when --nosal is set
|
|
3
3
|
* [FROM]: Depends on core/extensions/types.ts (ToolExecutionStartEvent, ToolExecutionEndEvent), core/runtime/turn-context.ts (publishes structuralAnchor), extensions/defaults/sal/terrain.ts, anchors.ts, weights.ts, eval/index.ts (pluggable adapters)
|
|
4
4
|
* [TO]: Loaded by builtin-extensions.ts as a default extension entry point
|
|
5
|
-
* [HERE]: extensions/defaults/sal/index.ts - pluggable Structural Anchor Localization (SAL) extension; emits run_start/turn_anchor/tool_trace/run_end eval events with best-effort flush/close isolation; tool_trace captures per-turn tool usage
|
|
5
|
+
* [HERE]: extensions/defaults/sal/index.ts - pluggable Structural Anchor Localization (SAL) extension; emits run_start/turn_anchor/tool_trace/run_end eval events with best-effort flush/close isolation; tool_trace captures per-turn tool usage and loop outcome for self-awareness analytics
|
|
6
6
|
*/
|
|
7
7
|
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
8
8
|
import { homedir } from "node:os";
|
|
@@ -549,6 +549,20 @@ export default async function salExtension(api) {
|
|
|
549
549
|
record.isError = event.isError;
|
|
550
550
|
}
|
|
551
551
|
});
|
|
552
|
+
api.on("agent_result", async (event, _ctx) => {
|
|
553
|
+
runtime.turn.agentResult = {
|
|
554
|
+
stopReason: event.stopReason,
|
|
555
|
+
turnCount: event.turnCount,
|
|
556
|
+
toolCallCount: event.toolCallCount,
|
|
557
|
+
durationMs: event.durationMs,
|
|
558
|
+
usage: event.usage,
|
|
559
|
+
permissionDenialCount: event.permissionDenialCount,
|
|
560
|
+
permissionDenials: event.permissionDenials,
|
|
561
|
+
lastTransition: event.lastTransition,
|
|
562
|
+
errorMessage: event.errorMessage,
|
|
563
|
+
errorSubtype: event.errorSubtype,
|
|
564
|
+
};
|
|
565
|
+
});
|
|
552
566
|
api.on("agent_end", async (_event, _ctx) => {
|
|
553
567
|
const turnDuration = Math.max(0, Date.now() - runtime.turn.startedAtMs);
|
|
554
568
|
const taskRes = runtime.turn.taskResolution;
|
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
* [WHO]: Provides BuildMeta, ToolCallRecord, TurnState, SalDiagnosticReporter, SalRuntime shared contracts for the SAL extension
|
|
3
3
|
* [FROM]: Depends on eval sink types, SAL anchors/terrain/weights types for runtime state shape
|
|
4
4
|
* [TO]: Consumed by extensions/defaults/sal/index.ts plus SAL config, trace, and context helpers
|
|
5
|
-
* [HERE]: extensions/defaults/sal/sal-runtime.ts - runtime contract boundary for Structural Anchor Localization modules
|
|
5
|
+
* [HERE]: extensions/defaults/sal/sal-runtime.ts - runtime contract boundary for Structural Anchor Localization modules, including per-turn loop outcome state
|
|
6
6
|
*/
|
|
7
7
|
import type { CreateEvalSinkOptions, EvalAdapterId, EvalSink, EvalVariant } from "./eval/index.js";
|
|
8
|
+
import type { AgentRunResult } from "@pencil-agent/agent-core";
|
|
8
9
|
import type { AnchorResolution } from "./anchors.js";
|
|
9
10
|
import type { TerrainSnapshot } from "./terrain.js";
|
|
10
11
|
import type { SalWeights } from "./weights.js";
|
|
@@ -24,6 +25,7 @@ export interface TurnState {
|
|
|
24
25
|
turnId: number;
|
|
25
26
|
startedAtMs: number;
|
|
26
27
|
taskResolution?: AnchorResolution;
|
|
28
|
+
agentResult?: AgentRunResult;
|
|
27
29
|
touchedFiles: Set<string>;
|
|
28
30
|
toolCalls: ToolCallRecord[];
|
|
29
31
|
prompt?: string;
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
* [WHO]: Provides BuildMeta, ToolCallRecord, TurnState, SalDiagnosticReporter, SalRuntime shared contracts for the SAL extension
|
|
3
3
|
* [FROM]: Depends on eval sink types, SAL anchors/terrain/weights types for runtime state shape
|
|
4
4
|
* [TO]: Consumed by extensions/defaults/sal/index.ts plus SAL config, trace, and context helpers
|
|
5
|
-
* [HERE]: extensions/defaults/sal/sal-runtime.ts - runtime contract boundary for Structural Anchor Localization modules
|
|
5
|
+
* [HERE]: extensions/defaults/sal/sal-runtime.ts - runtime contract boundary for Structural Anchor Localization modules, including per-turn loop outcome state
|
|
6
6
|
*/
|
|
7
7
|
export {};
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* [WHO]: Provides SAL tool-path extraction, task intent inference, and bounded tool_trace payload construction
|
|
3
3
|
* [FROM]: Depends on node path helpers and terrain path normalization
|
|
4
4
|
* [TO]: Consumed by extensions/defaults/sal/index.ts and SAL tool trace tests
|
|
5
|
-
* [HERE]: extensions/defaults/sal/sal-trace.ts - per-turn tool analytics boundary for Structural Anchor Localization
|
|
5
|
+
* [HERE]: extensions/defaults/sal/sal-trace.ts - per-turn tool and loop-outcome analytics boundary for Structural Anchor Localization
|
|
6
6
|
*/
|
|
7
7
|
import type { TurnState } from "./sal-runtime.js";
|
|
8
8
|
export type TaskIntent = "fix" | "feat" | "refactor" | "explain" | "explore" | "unknown";
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* [WHO]: Provides SAL tool-path extraction, task intent inference, and bounded tool_trace payload construction
|
|
3
3
|
* [FROM]: Depends on node path helpers and terrain path normalization
|
|
4
4
|
* [TO]: Consumed by extensions/defaults/sal/index.ts and SAL tool trace tests
|
|
5
|
-
* [HERE]: extensions/defaults/sal/sal-trace.ts - per-turn tool analytics boundary for Structural Anchor Localization
|
|
5
|
+
* [HERE]: extensions/defaults/sal/sal-trace.ts - per-turn tool and loop-outcome analytics boundary for Structural Anchor Localization
|
|
6
6
|
*/
|
|
7
7
|
import { isAbsolute, join, relative } from "node:path";
|
|
8
8
|
import { toPosixPath } from "./terrain.js";
|
|
@@ -108,7 +108,7 @@ export function buildToolTracePayload(turn, turnDuration) {
|
|
|
108
108
|
}));
|
|
109
109
|
const sequence = turn.toolCalls.slice(0, MAX_TOOL_SEQUENCE).map((tc) => tc.tool);
|
|
110
110
|
const completedToolCalls = turn.toolCalls.filter((tc) => tc.endMs != null).length;
|
|
111
|
-
|
|
111
|
+
const payload = {
|
|
112
112
|
turn_id: turn.turnId,
|
|
113
113
|
tool_calls: summarizedTools,
|
|
114
114
|
tool_sequence: sequence,
|
|
@@ -126,4 +126,15 @@ export function buildToolTracePayload(turn, turnDuration) {
|
|
|
126
126
|
truncated_tool_summary: Math.max(0, toolSummary.size - summarizedTools.length),
|
|
127
127
|
duration_ms: turnDuration,
|
|
128
128
|
};
|
|
129
|
+
if (turn.agentResult) {
|
|
130
|
+
payload.agent_loop = {
|
|
131
|
+
stop_reason: turn.agentResult.stopReason,
|
|
132
|
+
turn_count: turn.agentResult.turnCount,
|
|
133
|
+
tool_call_count: turn.agentResult.toolCallCount,
|
|
134
|
+
duration_ms: turn.agentResult.durationMs,
|
|
135
|
+
permission_denial_count: turn.agentResult.permissionDenialCount ?? 0,
|
|
136
|
+
last_transition_reason: turn.agentResult.lastTransition?.reason,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
return payload;
|
|
129
140
|
}
|
package/dist/main.js
CHANGED
|
@@ -515,6 +515,12 @@ function buildSessionOptions(parsed, scopedModels, sessionManager, modelRegistry
|
|
|
515
515
|
if (parsed.thinking) {
|
|
516
516
|
options.thinkingLevel = parsed.thinking;
|
|
517
517
|
}
|
|
518
|
+
if (parsed.agentLoopFramework) {
|
|
519
|
+
options.agentLoopFramework = parsed.agentLoopFramework;
|
|
520
|
+
}
|
|
521
|
+
if (parsed.loopPolicy) {
|
|
522
|
+
options.loopPolicy = parsed.loopPolicy;
|
|
523
|
+
}
|
|
518
524
|
// Scoped models for Ctrl+P cycling - fill in default thinking level for models without explicit level
|
|
519
525
|
if (scopedModels.length > 0) {
|
|
520
526
|
const defaultThinkingLevel = settingsManager.getDefaultThinkingLevel() ?? DEFAULT_THINKING_LEVEL;
|
|
@@ -894,16 +900,19 @@ export async function main(args) {
|
|
|
894
900
|
await mode.run();
|
|
895
901
|
}
|
|
896
902
|
else {
|
|
897
|
-
await runPrintMode(session, {
|
|
903
|
+
const printResult = await runPrintMode(session, {
|
|
898
904
|
mode,
|
|
899
905
|
messages: parsed.messages,
|
|
900
906
|
initialMessage,
|
|
901
907
|
initialImages,
|
|
908
|
+
printLoopResult: parsed.printLoopResult,
|
|
909
|
+
failOnAgentError: parsed.failOnAgentError,
|
|
910
|
+
failOnToolDenial: parsed.failOnToolDenial,
|
|
902
911
|
});
|
|
903
912
|
stopThemeWatcher();
|
|
904
913
|
if (process.stdout.writableLength > 0) {
|
|
905
914
|
await new Promise((resolve) => process.stdout.once("drain", resolve));
|
|
906
915
|
}
|
|
907
|
-
process.exit(
|
|
916
|
+
process.exit(printResult.exitCode);
|
|
908
917
|
}
|
|
909
918
|
}
|