@pencil-agent/nano-pencil 2.0.0-beta.2 → 2.0.0-beta.4
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/node_modules/@pencil-agent/agent-core/dist/agent-loop-continuations.d.ts +17 -0
- package/dist/node_modules/@pencil-agent/agent-core/dist/agent-loop-continuations.js +60 -0
- package/dist/node_modules/@pencil-agent/agent-core/dist/agent-loop-stream-events.d.ts +19 -0
- package/dist/node_modules/@pencil-agent/agent-core/dist/agent-loop-stream-events.js +55 -0
- package/dist/node_modules/@pencil-agent/agent-core/dist/agent-loop-tool-results.d.ts +10 -0
- package/dist/node_modules/@pencil-agent/agent-core/dist/agent-loop-tool-results.js +137 -0
- package/dist/node_modules/@pencil-agent/agent-core/dist/agent-loop-tool-summaries.d.ts +22 -0
- package/dist/node_modules/@pencil-agent/agent-core/dist/agent-loop-tool-summaries.js +64 -0
- package/dist/node_modules/@pencil-agent/agent-core/dist/agent-loop.d.ts +26 -0
- package/dist/node_modules/@pencil-agent/agent-core/dist/agent-loop.js +913 -0
- package/dist/node_modules/@pencil-agent/agent-core/dist/agent-run-result.d.ts +9 -0
- package/dist/node_modules/@pencil-agent/agent-core/dist/agent-run-result.js +32 -0
- package/dist/node_modules/@pencil-agent/agent-core/dist/agent.d.ts +215 -0
- package/dist/node_modules/@pencil-agent/agent-core/dist/agent.js +522 -0
- package/dist/node_modules/@pencil-agent/agent-core/dist/errors.d.ts +62 -0
- package/dist/node_modules/@pencil-agent/agent-core/dist/errors.js +146 -0
- package/dist/node_modules/@pencil-agent/agent-core/dist/index.d.ts +14 -0
- package/dist/node_modules/@pencil-agent/agent-core/dist/index.js +19 -0
- package/dist/node_modules/@pencil-agent/agent-core/dist/proxy.d.ts +91 -0
- package/dist/node_modules/@pencil-agent/agent-core/dist/proxy.js +279 -0
- package/dist/node_modules/@pencil-agent/agent-core/dist/structured-adaptive-agent-loop.d.ts +15 -0
- package/dist/node_modules/@pencil-agent/agent-core/dist/structured-adaptive-agent-loop.js +625 -0
- package/dist/node_modules/@pencil-agent/agent-core/dist/structured-adaptive-streaming-tool-executor.d.ts +33 -0
- package/dist/node_modules/@pencil-agent/agent-core/dist/structured-adaptive-streaming-tool-executor.js +189 -0
- package/dist/node_modules/@pencil-agent/agent-core/dist/structured-adaptive-tool-orchestration.d.ts +35 -0
- package/dist/node_modules/@pencil-agent/agent-core/dist/structured-adaptive-tool-orchestration.js +319 -0
- package/dist/node_modules/@pencil-agent/agent-core/dist/types.d.ts +417 -0
- package/dist/node_modules/@pencil-agent/agent-core/dist/types.js +13 -0
- package/dist/node_modules/@pencil-agent/agent-core/package.json +28 -0
- package/dist/node_modules/@pencil-agent/ai/dist/api-registry.d.ts +27 -0
- package/dist/node_modules/@pencil-agent/ai/dist/api-registry.js +152 -0
- package/dist/node_modules/@pencil-agent/ai/dist/cli.d.ts +2 -0
- package/dist/node_modules/@pencil-agent/ai/dist/cli.js +121 -0
- package/dist/node_modules/@pencil-agent/ai/dist/config-path.d.ts +1 -0
- package/dist/node_modules/@pencil-agent/ai/dist/config-path.js +17 -0
- package/dist/node_modules/@pencil-agent/ai/dist/debug-logger.d.ts +94 -0
- package/dist/node_modules/@pencil-agent/ai/dist/debug-logger.js +218 -0
- package/dist/node_modules/@pencil-agent/ai/dist/env-api-keys.d.ts +8 -0
- package/dist/node_modules/@pencil-agent/ai/dist/env-api-keys.js +107 -0
- package/dist/node_modules/@pencil-agent/ai/dist/env.d.ts +7 -0
- package/dist/node_modules/@pencil-agent/ai/dist/env.js +7 -0
- package/dist/node_modules/@pencil-agent/ai/dist/events.d.ts +8 -0
- package/dist/node_modules/@pencil-agent/ai/dist/events.js +7 -0
- package/dist/node_modules/@pencil-agent/ai/dist/index.d.ts +27 -0
- package/dist/node_modules/@pencil-agent/ai/dist/index.js +20 -0
- package/dist/node_modules/@pencil-agent/ai/dist/json.d.ts +7 -0
- package/dist/node_modules/@pencil-agent/ai/dist/json.js +7 -0
- package/dist/node_modules/@pencil-agent/ai/dist/models.d.ts +31 -0
- package/dist/node_modules/@pencil-agent/ai/dist/models.generated.d.ts +15159 -0
- package/dist/node_modules/@pencil-agent/ai/dist/models.generated.js +14928 -0
- package/dist/node_modules/@pencil-agent/ai/dist/models.js +60 -0
- package/dist/node_modules/@pencil-agent/ai/dist/overflow.d.ts +7 -0
- package/dist/node_modules/@pencil-agent/ai/dist/overflow.js +7 -0
- package/dist/node_modules/@pencil-agent/ai/dist/providers/amazon-bedrock.d.ts +20 -0
- package/dist/node_modules/@pencil-agent/ai/dist/providers/amazon-bedrock.js +606 -0
- package/dist/node_modules/@pencil-agent/ai/dist/providers/anthropic.d.ts +38 -0
- package/dist/node_modules/@pencil-agent/ai/dist/providers/anthropic.js +737 -0
- package/dist/node_modules/@pencil-agent/ai/dist/providers/azure-openai-responses.d.ts +21 -0
- package/dist/node_modules/@pencil-agent/ai/dist/providers/azure-openai-responses.js +193 -0
- package/dist/node_modules/@pencil-agent/ai/dist/providers/github-copilot-headers.d.ts +13 -0
- package/dist/node_modules/@pencil-agent/ai/dist/providers/github-copilot-headers.js +34 -0
- package/dist/node_modules/@pencil-agent/ai/dist/providers/google-gemini-cli.d.ts +79 -0
- package/dist/node_modules/@pencil-agent/ai/dist/providers/google-gemini-cli.js +753 -0
- package/dist/node_modules/@pencil-agent/ai/dist/providers/google-shared.d.ts +70 -0
- package/dist/node_modules/@pencil-agent/ai/dist/providers/google-shared.js +311 -0
- package/dist/node_modules/@pencil-agent/ai/dist/providers/google-vertex.d.ts +20 -0
- package/dist/node_modules/@pencil-agent/ai/dist/providers/google-vertex.js +380 -0
- package/dist/node_modules/@pencil-agent/ai/dist/providers/google.d.ts +18 -0
- package/dist/node_modules/@pencil-agent/ai/dist/providers/google.js +360 -0
- package/dist/node_modules/@pencil-agent/ai/dist/providers/openai-codex-responses.d.ts +8 -0
- package/dist/node_modules/@pencil-agent/ai/dist/providers/openai-codex-responses.js +704 -0
- package/dist/node_modules/@pencil-agent/ai/dist/providers/openai-completions.d.ts +20 -0
- package/dist/node_modules/@pencil-agent/ai/dist/providers/openai-completions.js +870 -0
- package/dist/node_modules/@pencil-agent/ai/dist/providers/openai-responses-shared.d.ts +22 -0
- package/dist/node_modules/@pencil-agent/ai/dist/providers/openai-responses-shared.js +432 -0
- package/dist/node_modules/@pencil-agent/ai/dist/providers/openai-responses.d.ts +19 -0
- package/dist/node_modules/@pencil-agent/ai/dist/providers/openai-responses.js +207 -0
- package/dist/node_modules/@pencil-agent/ai/dist/providers/register-builtins.d.ts +8 -0
- package/dist/node_modules/@pencil-agent/ai/dist/providers/register-builtins.js +86 -0
- package/dist/node_modules/@pencil-agent/ai/dist/providers/simple-options.d.ts +13 -0
- package/dist/node_modules/@pencil-agent/ai/dist/providers/simple-options.js +40 -0
- package/dist/node_modules/@pencil-agent/ai/dist/providers/transform-messages.d.ts +13 -0
- package/dist/node_modules/@pencil-agent/ai/dist/providers/transform-messages.js +175 -0
- package/dist/node_modules/@pencil-agent/ai/dist/registry.d.ts +8 -0
- package/dist/node_modules/@pencil-agent/ai/dist/registry.js +8 -0
- package/dist/node_modules/@pencil-agent/ai/dist/schema.d.ts +10 -0
- package/dist/node_modules/@pencil-agent/ai/dist/schema.js +9 -0
- package/dist/node_modules/@pencil-agent/ai/dist/stream.d.ts +25 -0
- package/dist/node_modules/@pencil-agent/ai/dist/stream.js +324 -0
- package/dist/node_modules/@pencil-agent/ai/dist/types.d.ts +306 -0
- package/dist/node_modules/@pencil-agent/ai/dist/types.js +7 -0
- package/dist/node_modules/@pencil-agent/ai/dist/utils/event-stream-types.d.ts +12 -0
- package/dist/node_modules/@pencil-agent/ai/dist/utils/event-stream-types.js +7 -0
- package/dist/node_modules/@pencil-agent/ai/dist/utils/event-stream.d.ts +31 -0
- package/dist/node_modules/@pencil-agent/ai/dist/utils/event-stream.js +98 -0
- package/dist/node_modules/@pencil-agent/ai/dist/utils/http-proxy.d.ts +13 -0
- package/dist/node_modules/@pencil-agent/ai/dist/utils/http-proxy.js +20 -0
- package/dist/node_modules/@pencil-agent/ai/dist/utils/json-parse.d.ts +14 -0
- package/dist/node_modules/@pencil-agent/ai/dist/utils/json-parse.js +34 -0
- package/dist/node_modules/@pencil-agent/ai/dist/utils/oauth/anthropic.d.ts +22 -0
- package/dist/node_modules/@pencil-agent/ai/dist/utils/oauth/anthropic.js +109 -0
- package/dist/node_modules/@pencil-agent/ai/dist/utils/oauth/decode-credential.d.ts +12 -0
- package/dist/node_modules/@pencil-agent/ai/dist/utils/oauth/decode-credential.js +25 -0
- package/dist/node_modules/@pencil-agent/ai/dist/utils/oauth/github-copilot.d.ts +35 -0
- package/dist/node_modules/@pencil-agent/ai/dist/utils/oauth/github-copilot.js +286 -0
- package/dist/node_modules/@pencil-agent/ai/dist/utils/oauth/google-antigravity.d.ts +31 -0
- package/dist/node_modules/@pencil-agent/ai/dist/utils/oauth/google-antigravity.js +378 -0
- package/dist/node_modules/@pencil-agent/ai/dist/utils/oauth/google-gemini-cli.d.ts +31 -0
- package/dist/node_modules/@pencil-agent/ai/dist/utils/oauth/google-gemini-cli.js +483 -0
- package/dist/node_modules/@pencil-agent/ai/dist/utils/oauth/index.d.ts +60 -0
- package/dist/node_modules/@pencil-agent/ai/dist/utils/oauth/index.js +131 -0
- package/dist/node_modules/@pencil-agent/ai/dist/utils/oauth/openai-codex.d.ts +39 -0
- package/dist/node_modules/@pencil-agent/ai/dist/utils/oauth/openai-codex.js +385 -0
- package/dist/node_modules/@pencil-agent/ai/dist/utils/oauth/pkce.d.ts +18 -0
- package/dist/node_modules/@pencil-agent/ai/dist/utils/oauth/pkce.js +36 -0
- package/dist/node_modules/@pencil-agent/ai/dist/utils/oauth/types.d.ts +52 -0
- package/dist/node_modules/@pencil-agent/ai/dist/utils/oauth/types.js +7 -0
- package/dist/node_modules/@pencil-agent/ai/dist/utils/overflow.d.ts +57 -0
- package/dist/node_modules/@pencil-agent/ai/dist/utils/overflow.js +120 -0
- package/dist/node_modules/@pencil-agent/ai/dist/utils/sanitize-unicode.d.ts +16 -0
- package/dist/node_modules/@pencil-agent/ai/dist/utils/sanitize-unicode.js +20 -0
- package/dist/node_modules/@pencil-agent/ai/dist/utils/typebox-helpers.d.ts +22 -0
- package/dist/node_modules/@pencil-agent/ai/dist/utils/typebox-helpers.js +26 -0
- package/dist/node_modules/@pencil-agent/ai/dist/utils/validation.d.ts +23 -0
- package/dist/node_modules/@pencil-agent/ai/dist/utils/validation.js +78 -0
- package/dist/node_modules/@pencil-agent/ai/package.json +106 -0
- package/dist/node_modules/@pencil-agent/tui/dist/autocomplete.d.ts +62 -0
- package/dist/node_modules/@pencil-agent/tui/dist/autocomplete.js +624 -0
- package/dist/node_modules/@pencil-agent/tui/dist/components/box.d.ts +27 -0
- package/dist/node_modules/@pencil-agent/tui/dist/components/box.js +109 -0
- package/dist/node_modules/@pencil-agent/tui/dist/components/cancellable-loader.d.ts +27 -0
- package/dist/node_modules/@pencil-agent/tui/dist/components/cancellable-loader.js +40 -0
- package/dist/node_modules/@pencil-agent/tui/dist/components/editor.d.ts +218 -0
- package/dist/node_modules/@pencil-agent/tui/dist/components/editor.js +1697 -0
- package/dist/node_modules/@pencil-agent/tui/dist/components/image.d.ts +33 -0
- package/dist/node_modules/@pencil-agent/tui/dist/components/image.js +74 -0
- package/dist/node_modules/@pencil-agent/tui/dist/components/input.d.ts +42 -0
- package/dist/node_modules/@pencil-agent/tui/dist/components/input.js +438 -0
- package/dist/node_modules/@pencil-agent/tui/dist/components/loader.d.ts +26 -0
- package/dist/node_modules/@pencil-agent/tui/dist/components/loader.js +54 -0
- package/dist/node_modules/@pencil-agent/tui/dist/components/markdown.d.ts +100 -0
- package/dist/node_modules/@pencil-agent/tui/dist/components/markdown.js +634 -0
- package/dist/node_modules/@pencil-agent/tui/dist/components/select-list.d.ts +37 -0
- package/dist/node_modules/@pencil-agent/tui/dist/components/select-list.js +157 -0
- package/dist/node_modules/@pencil-agent/tui/dist/components/settings-list.d.ts +55 -0
- package/dist/node_modules/@pencil-agent/tui/dist/components/settings-list.js +190 -0
- package/dist/node_modules/@pencil-agent/tui/dist/components/spacer.d.ts +17 -0
- package/dist/node_modules/@pencil-agent/tui/dist/components/spacer.js +28 -0
- package/dist/node_modules/@pencil-agent/tui/dist/components/text.d.ts +24 -0
- package/dist/node_modules/@pencil-agent/tui/dist/components/text.js +94 -0
- package/dist/node_modules/@pencil-agent/tui/dist/components/truncated-text.d.ts +18 -0
- package/dist/node_modules/@pencil-agent/tui/dist/components/truncated-text.js +56 -0
- package/dist/node_modules/@pencil-agent/tui/dist/editor-component.d.ts +51 -0
- package/dist/node_modules/@pencil-agent/tui/dist/editor-component.js +7 -0
- package/dist/node_modules/@pencil-agent/tui/dist/fuzzy.d.ts +32 -0
- package/dist/node_modules/@pencil-agent/tui/dist/fuzzy.js +152 -0
- package/dist/node_modules/@pencil-agent/tui/dist/index.d.ts +28 -0
- package/dist/node_modules/@pencil-agent/tui/dist/index.js +37 -0
- package/dist/node_modules/@pencil-agent/tui/dist/keybindings.d.ts +44 -0
- package/dist/node_modules/@pencil-agent/tui/dist/keybindings.js +119 -0
- package/dist/node_modules/@pencil-agent/tui/dist/keys.d.ts +149 -0
- package/dist/node_modules/@pencil-agent/tui/dist/keys.js +948 -0
- package/dist/node_modules/@pencil-agent/tui/dist/kill-ring.d.ts +33 -0
- package/dist/node_modules/@pencil-agent/tui/dist/kill-ring.js +49 -0
- package/dist/node_modules/@pencil-agent/tui/dist/stdin-buffer.d.ts +38 -0
- package/dist/node_modules/@pencil-agent/tui/dist/stdin-buffer.js +307 -0
- package/dist/node_modules/@pencil-agent/tui/dist/terminal-image.d.ts +73 -0
- package/dist/node_modules/@pencil-agent/tui/dist/terminal-image.js +287 -0
- package/dist/node_modules/@pencil-agent/tui/dist/terminal.d.ts +86 -0
- package/dist/node_modules/@pencil-agent/tui/dist/terminal.js +266 -0
- package/dist/node_modules/@pencil-agent/tui/dist/tui.d.ts +219 -0
- package/dist/node_modules/@pencil-agent/tui/dist/tui.js +1001 -0
- package/dist/node_modules/@pencil-agent/tui/dist/undo-stack.d.ts +22 -0
- package/dist/node_modules/@pencil-agent/tui/dist/undo-stack.js +30 -0
- package/dist/node_modules/@pencil-agent/tui/dist/utils.d.ts +83 -0
- package/dist/node_modules/@pencil-agent/tui/dist/utils.js +811 -0
- package/dist/node_modules/@pencil-agent/tui/package.json +37 -0
- package/package.json +3 -2
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured-adaptive streaming tool executor.
|
|
3
|
+
* Starts complete streamed tool calls before the assistant response finishes,
|
|
4
|
+
* while preserving ordered tool_result emission for the next model turn.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* [WHO]: StructuredAdaptiveStreamingToolExecutor
|
|
8
|
+
* [FROM]: Depends on @pencil-agent/ai, ./types, ./structured-adaptive-tool-orchestration
|
|
9
|
+
* [TO]: Consumed by ./structured-adaptive-agent-loop.ts
|
|
10
|
+
* [HERE]: core/lib/agent-core/src/structured-adaptive-streaming-tool-executor.ts - streaming tool scheduling for weak-model-compatible loop
|
|
11
|
+
*/
|
|
12
|
+
import { buildToolMap, isStructuredAdaptiveToolCallConcurrencySafe, resolveStructuredAdaptiveToolInterruptBehavior, runStructuredAdaptiveToolUse, } from "./structured-adaptive-tool-orchestration.js";
|
|
13
|
+
export class StructuredAdaptiveStreamingToolExecutor {
|
|
14
|
+
stream;
|
|
15
|
+
canUseTool;
|
|
16
|
+
toolByName;
|
|
17
|
+
records = [];
|
|
18
|
+
maxConcurrency;
|
|
19
|
+
discardedReason;
|
|
20
|
+
parentAborted = false;
|
|
21
|
+
parentAbortReason;
|
|
22
|
+
constructor(tools, signal, stream, maxConcurrency, canUseTool) {
|
|
23
|
+
this.stream = stream;
|
|
24
|
+
this.canUseTool = canUseTool;
|
|
25
|
+
this.toolByName = buildToolMap(tools);
|
|
26
|
+
this.maxConcurrency = Math.max(1, Math.floor(maxConcurrency));
|
|
27
|
+
if (signal?.aborted) {
|
|
28
|
+
this.parentAborted = true;
|
|
29
|
+
this.parentAbortReason = signal.reason;
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
signal?.addEventListener("abort", () => {
|
|
33
|
+
this.parentAborted = true;
|
|
34
|
+
this.parentAbortReason = signal.reason;
|
|
35
|
+
for (const record of this.records) {
|
|
36
|
+
if (record.interruptBehavior === "cancel" && !record.abortController.signal.aborted) {
|
|
37
|
+
record.abortController.abort(signal.reason);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}, { once: true });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
get size() {
|
|
44
|
+
return this.records.length;
|
|
45
|
+
}
|
|
46
|
+
addTool(toolCall) {
|
|
47
|
+
if (this.records.some((record) => record.toolCall.id === toolCall.id))
|
|
48
|
+
return;
|
|
49
|
+
const tool = this.toolByName.get(toolCall.name);
|
|
50
|
+
const abortController = new AbortController();
|
|
51
|
+
const interruptBehavior = resolveStructuredAdaptiveToolInterruptBehavior(toolCall, tool);
|
|
52
|
+
if (this.parentAborted && interruptBehavior === "cancel") {
|
|
53
|
+
abortController.abort(this.parentAbortReason);
|
|
54
|
+
}
|
|
55
|
+
this.records.push({
|
|
56
|
+
toolCall,
|
|
57
|
+
tool,
|
|
58
|
+
isConcurrencySafe: isStructuredAdaptiveToolCallConcurrencySafe(toolCall, tool),
|
|
59
|
+
interruptBehavior,
|
|
60
|
+
status: "queued",
|
|
61
|
+
abortController,
|
|
62
|
+
contextMessages: [],
|
|
63
|
+
});
|
|
64
|
+
this.processQueue();
|
|
65
|
+
}
|
|
66
|
+
async drain() {
|
|
67
|
+
this.processQueue();
|
|
68
|
+
while (this.records.some((record) => record.status !== "completed")) {
|
|
69
|
+
const running = this.records
|
|
70
|
+
.filter((record) => record.status === "executing" && record.promise)
|
|
71
|
+
.map((record) => record.promise);
|
|
72
|
+
if (running.length === 0) {
|
|
73
|
+
this.processQueue();
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
await Promise.race(running);
|
|
77
|
+
this.processQueue();
|
|
78
|
+
}
|
|
79
|
+
const toolResults = this.records.map((record) => record.toolResult);
|
|
80
|
+
return {
|
|
81
|
+
toolResults,
|
|
82
|
+
contextMessages: this.records.flatMap((record) => record.contextMessages),
|
|
83
|
+
permissionDenials: extractPermissionDenials(toolResults),
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
async discardAndDrain(reason, abortMode = "all") {
|
|
87
|
+
this.discardedReason = reason;
|
|
88
|
+
for (const record of this.records) {
|
|
89
|
+
if (record.status === "executing" &&
|
|
90
|
+
(abortMode === "all" || record.interruptBehavior === "cancel") &&
|
|
91
|
+
!record.abortController.signal.aborted) {
|
|
92
|
+
record.abortController.abort(reason);
|
|
93
|
+
}
|
|
94
|
+
if (record.status === "queued") {
|
|
95
|
+
this.completeWithSyntheticError(record, reason);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return this.drain();
|
|
99
|
+
}
|
|
100
|
+
processQueue() {
|
|
101
|
+
for (const record of this.records) {
|
|
102
|
+
if (record.status !== "queued")
|
|
103
|
+
continue;
|
|
104
|
+
if (this.discardedReason) {
|
|
105
|
+
this.completeWithSyntheticError(record, this.discardedReason);
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
if (!this.canStart(record)) {
|
|
109
|
+
if (!record.isConcurrencySafe)
|
|
110
|
+
return;
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
this.start(record);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
canStart(record) {
|
|
117
|
+
const executing = this.records.filter((candidate) => candidate.status === "executing");
|
|
118
|
+
if (record.isConcurrencySafe) {
|
|
119
|
+
return (executing.length < this.maxConcurrency &&
|
|
120
|
+
executing.every((candidate) => candidate.isConcurrencySafe));
|
|
121
|
+
}
|
|
122
|
+
return executing.length === 0;
|
|
123
|
+
}
|
|
124
|
+
start(record) {
|
|
125
|
+
record.status = "executing";
|
|
126
|
+
record.promise = runStructuredAdaptiveToolUse(record.toolCall, record.tool, record.abortController.signal, this.stream, this.canUseTool)
|
|
127
|
+
.then((result) => {
|
|
128
|
+
record.toolResult = result.toolResult;
|
|
129
|
+
record.contextMessages = result.contextMessages;
|
|
130
|
+
})
|
|
131
|
+
.finally(() => {
|
|
132
|
+
record.status = "completed";
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
completeWithSyntheticError(record, reason) {
|
|
136
|
+
const startedAt = Date.now();
|
|
137
|
+
const result = {
|
|
138
|
+
content: [{ type: "text", text: `Tool discarded because ${reason}.` }],
|
|
139
|
+
details: {
|
|
140
|
+
errorType: "streaming_tool_discarded",
|
|
141
|
+
reason,
|
|
142
|
+
toolName: record.tool?.name ?? record.toolCall.name,
|
|
143
|
+
toolCallId: record.toolCall.id,
|
|
144
|
+
},
|
|
145
|
+
};
|
|
146
|
+
this.stream.push({
|
|
147
|
+
type: "tool_execution_start",
|
|
148
|
+
toolCallId: record.toolCall.id,
|
|
149
|
+
toolName: record.toolCall.name,
|
|
150
|
+
args: record.toolCall.arguments,
|
|
151
|
+
});
|
|
152
|
+
this.stream.push({
|
|
153
|
+
type: "tool_execution_end",
|
|
154
|
+
toolCallId: record.toolCall.id,
|
|
155
|
+
toolName: record.toolCall.name,
|
|
156
|
+
result,
|
|
157
|
+
isError: true,
|
|
158
|
+
durationMs: Date.now() - startedAt,
|
|
159
|
+
});
|
|
160
|
+
record.toolResult = {
|
|
161
|
+
role: "toolResult",
|
|
162
|
+
toolCallId: record.toolCall.id,
|
|
163
|
+
toolName: record.toolCall.name,
|
|
164
|
+
content: result.content,
|
|
165
|
+
details: result.details,
|
|
166
|
+
isError: true,
|
|
167
|
+
timestamp: Date.now(),
|
|
168
|
+
};
|
|
169
|
+
record.contextMessages = [];
|
|
170
|
+
record.status = "completed";
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
function extractPermissionDenials(toolResults) {
|
|
174
|
+
const denials = [];
|
|
175
|
+
for (const result of toolResults) {
|
|
176
|
+
const details = result.details;
|
|
177
|
+
if (!details || typeof details !== "object")
|
|
178
|
+
continue;
|
|
179
|
+
if (details.errorType !== "permission_denied")
|
|
180
|
+
continue;
|
|
181
|
+
const reason = details.reason;
|
|
182
|
+
denials.push({
|
|
183
|
+
toolCallId: result.toolCallId,
|
|
184
|
+
toolName: result.toolName,
|
|
185
|
+
reason: typeof reason === "string" && reason.length > 0 ? reason : undefined,
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
return denials;
|
|
189
|
+
}
|
package/dist/node_modules/@pencil-agent/agent-core/dist/structured-adaptive-tool-orchestration.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured-adaptive tool orchestration for the selectable structured loop.
|
|
3
|
+
* Batches concurrency-safe tools, keeps stateful tools serial, and returns
|
|
4
|
+
* ordered tool_result messages matching assistant tool_use order.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* [WHO]: runStructuredAdaptiveTools, partitionStructuredAdaptiveToolCalls, StructuredAdaptiveToolCall
|
|
8
|
+
* [FROM]: Depends on @pencil-agent/ai, ./types, ./errors
|
|
9
|
+
* [TO]: Consumed by ./structured-adaptive-agent-loop.ts and agent-core tests
|
|
10
|
+
* [HERE]: core/lib/agent-core/src/structured-adaptive-tool-orchestration.ts - tool batching/execution layer for structured-adaptive loop
|
|
11
|
+
*/
|
|
12
|
+
import { type AssistantMessage, type ToolResultMessage } from "@pencil-agent/ai/types";
|
|
13
|
+
import { EventStream } from "@pencil-agent/ai/events";
|
|
14
|
+
import type { AgentEvent, AgentLoopConfig, AgentMessage, AgentTool, AgentToolPermissionDenial } from "./types.js";
|
|
15
|
+
export type StructuredAdaptiveToolCall = Extract<AssistantMessage["content"][number], {
|
|
16
|
+
type: "toolCall";
|
|
17
|
+
}>;
|
|
18
|
+
export interface StructuredAdaptiveToolRunResult {
|
|
19
|
+
toolResults: ToolResultMessage[];
|
|
20
|
+
contextMessages: AgentMessage[];
|
|
21
|
+
steeringMessages?: AgentMessage[];
|
|
22
|
+
permissionDenials: AgentToolPermissionDenial[];
|
|
23
|
+
}
|
|
24
|
+
interface StructuredAdaptiveToolUseResult {
|
|
25
|
+
toolResult: ToolResultMessage;
|
|
26
|
+
contextMessages: AgentMessage[];
|
|
27
|
+
}
|
|
28
|
+
export declare function runStructuredAdaptiveTools(toolCalls: StructuredAdaptiveToolCall[], tools: AgentTool<any>[] | undefined, signal: AbortSignal | undefined, stream: EventStream<AgentEvent, AgentMessage[]>, getSteeringMessages?: AgentLoopConfig["getSteeringMessages"], maxConcurrency?: number, canUseTool?: AgentLoopConfig["canUseTool"]): Promise<StructuredAdaptiveToolRunResult>;
|
|
29
|
+
export declare function resolveMaxToolConcurrency(maxConcurrency: number | undefined): number;
|
|
30
|
+
export declare function buildToolMap(tools: AgentTool<any>[] | undefined): Map<string, AgentTool<any>>;
|
|
31
|
+
export declare function partitionStructuredAdaptiveToolCalls(toolCalls: StructuredAdaptiveToolCall[], toolByName: Map<string, AgentTool<any>>): StructuredAdaptiveToolCall[][];
|
|
32
|
+
export declare function isStructuredAdaptiveToolCallConcurrencySafe(toolCall: StructuredAdaptiveToolCall, tool: AgentTool<any> | undefined): boolean;
|
|
33
|
+
export declare function resolveStructuredAdaptiveToolInterruptBehavior(toolCall: StructuredAdaptiveToolCall, tool: AgentTool<any> | undefined): "cancel" | "block";
|
|
34
|
+
export declare function runStructuredAdaptiveToolUse(toolCall: StructuredAdaptiveToolCall, tool: AgentTool<any> | undefined, signal: AbortSignal | undefined, stream: EventStream<AgentEvent, AgentMessage[]>, canUseTool?: AgentLoopConfig["canUseTool"]): Promise<StructuredAdaptiveToolUseResult>;
|
|
35
|
+
export {};
|
package/dist/node_modules/@pencil-agent/agent-core/dist/structured-adaptive-tool-orchestration.js
ADDED
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured-adaptive tool orchestration for the selectable structured loop.
|
|
3
|
+
* Batches concurrency-safe tools, keeps stateful tools serial, and returns
|
|
4
|
+
* ordered tool_result messages matching assistant tool_use order.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* [WHO]: runStructuredAdaptiveTools, partitionStructuredAdaptiveToolCalls, StructuredAdaptiveToolCall
|
|
8
|
+
* [FROM]: Depends on @pencil-agent/ai, ./types, ./errors
|
|
9
|
+
* [TO]: Consumed by ./structured-adaptive-agent-loop.ts and agent-core tests
|
|
10
|
+
* [HERE]: core/lib/agent-core/src/structured-adaptive-tool-orchestration.ts - tool batching/execution layer for structured-adaptive loop
|
|
11
|
+
*/
|
|
12
|
+
import { validateToolArguments } from "@pencil-agent/ai/schema";
|
|
13
|
+
import { ToolNotFoundError } from "./errors.js";
|
|
14
|
+
const DEFAULT_SAFE_TOOL_NAMES = new Set([
|
|
15
|
+
"read",
|
|
16
|
+
"find",
|
|
17
|
+
"grep",
|
|
18
|
+
"ls",
|
|
19
|
+
"source",
|
|
20
|
+
"time",
|
|
21
|
+
"web_search",
|
|
22
|
+
"web_fetch",
|
|
23
|
+
"CronList",
|
|
24
|
+
]);
|
|
25
|
+
const DEFAULT_MAX_TOOL_CONCURRENCY = 10;
|
|
26
|
+
const MAX_TOOL_CONCURRENCY_ENV = "NANOPENCIL_MAX_TOOL_USE_CONCURRENCY";
|
|
27
|
+
export async function runStructuredAdaptiveTools(toolCalls, tools, signal, stream, getSteeringMessages, maxConcurrency, canUseTool) {
|
|
28
|
+
const results = [];
|
|
29
|
+
const contextMessages = [];
|
|
30
|
+
const permissionDenials = [];
|
|
31
|
+
const toolByName = buildToolMap(tools);
|
|
32
|
+
const batches = partitionStructuredAdaptiveToolCalls(toolCalls, toolByName);
|
|
33
|
+
let consumed = 0;
|
|
34
|
+
for (const batch of batches) {
|
|
35
|
+
const batchUses = await runToolBatch(batch, (toolCall) => runStructuredAdaptiveToolUse(toolCall, toolByName.get(toolCall.name), signal, stream, canUseTool), maxConcurrency);
|
|
36
|
+
const batchResults = batchUses.map((use) => use.toolResult);
|
|
37
|
+
results.push(...batchResults);
|
|
38
|
+
contextMessages.push(...batchUses.flatMap((use) => use.contextMessages));
|
|
39
|
+
permissionDenials.push(...extractPermissionDenials(batchResults));
|
|
40
|
+
consumed += batch.length;
|
|
41
|
+
if (getSteeringMessages) {
|
|
42
|
+
const steering = await getSteeringMessages();
|
|
43
|
+
if (steering.length > 0) {
|
|
44
|
+
for (const skipped of toolCalls.slice(consumed)) {
|
|
45
|
+
results.push(skipStructuredAdaptiveToolCall(skipped, stream));
|
|
46
|
+
}
|
|
47
|
+
return { toolResults: results, contextMessages, steeringMessages: steering, permissionDenials };
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return { toolResults: results, contextMessages, permissionDenials };
|
|
52
|
+
}
|
|
53
|
+
async function runToolBatch(items, run, maxConcurrency) {
|
|
54
|
+
const limit = resolveMaxToolConcurrency(maxConcurrency);
|
|
55
|
+
const results = new Array(items.length);
|
|
56
|
+
let nextIndex = 0;
|
|
57
|
+
async function worker() {
|
|
58
|
+
while (nextIndex < items.length) {
|
|
59
|
+
const index = nextIndex;
|
|
60
|
+
nextIndex += 1;
|
|
61
|
+
results[index] = await run(items[index]);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
const workerCount = Math.min(limit, items.length);
|
|
65
|
+
await Promise.all(Array.from({ length: workerCount }, () => worker()));
|
|
66
|
+
return results;
|
|
67
|
+
}
|
|
68
|
+
export function resolveMaxToolConcurrency(maxConcurrency) {
|
|
69
|
+
if (maxConcurrency !== undefined) {
|
|
70
|
+
return Math.max(1, Math.floor(maxConcurrency || DEFAULT_MAX_TOOL_CONCURRENCY));
|
|
71
|
+
}
|
|
72
|
+
const raw = typeof process !== "undefined" ? process.env[MAX_TOOL_CONCURRENCY_ENV] : undefined;
|
|
73
|
+
const parsed = raw ? Number.parseInt(raw, 10) : Number.NaN;
|
|
74
|
+
if (Number.isFinite(parsed) && parsed > 0) {
|
|
75
|
+
return Math.floor(parsed);
|
|
76
|
+
}
|
|
77
|
+
return DEFAULT_MAX_TOOL_CONCURRENCY;
|
|
78
|
+
}
|
|
79
|
+
export function buildToolMap(tools) {
|
|
80
|
+
const toolByName = new Map();
|
|
81
|
+
for (const tool of tools ?? []) {
|
|
82
|
+
toolByName.set(tool.name, tool);
|
|
83
|
+
for (const alias of tool.aliases ?? []) {
|
|
84
|
+
if (!toolByName.has(alias)) {
|
|
85
|
+
toolByName.set(alias, tool);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return toolByName;
|
|
90
|
+
}
|
|
91
|
+
export function partitionStructuredAdaptiveToolCalls(toolCalls, toolByName) {
|
|
92
|
+
const batches = [];
|
|
93
|
+
let safeBatch = [];
|
|
94
|
+
for (const toolCall of toolCalls) {
|
|
95
|
+
const tool = toolByName.get(toolCall.name);
|
|
96
|
+
if (isStructuredAdaptiveToolCallConcurrencySafe(toolCall, tool)) {
|
|
97
|
+
safeBatch.push(toolCall);
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
if (safeBatch.length > 0) {
|
|
101
|
+
batches.push(safeBatch);
|
|
102
|
+
safeBatch = [];
|
|
103
|
+
}
|
|
104
|
+
batches.push([toolCall]);
|
|
105
|
+
}
|
|
106
|
+
if (safeBatch.length > 0) {
|
|
107
|
+
batches.push(safeBatch);
|
|
108
|
+
}
|
|
109
|
+
return batches;
|
|
110
|
+
}
|
|
111
|
+
export function isStructuredAdaptiveToolCallConcurrencySafe(toolCall, tool) {
|
|
112
|
+
if (!tool)
|
|
113
|
+
return DEFAULT_SAFE_TOOL_NAMES.has(toolCall.name);
|
|
114
|
+
const safety = tool.isConcurrencySafe;
|
|
115
|
+
if (typeof safety === "function") {
|
|
116
|
+
try {
|
|
117
|
+
return safety(validateToolArguments(tool, toolCall));
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return safety ?? DEFAULT_SAFE_TOOL_NAMES.has(toolCall.name);
|
|
124
|
+
}
|
|
125
|
+
export function resolveStructuredAdaptiveToolInterruptBehavior(toolCall, tool) {
|
|
126
|
+
if (!tool)
|
|
127
|
+
return "block";
|
|
128
|
+
const behavior = tool?.interruptBehavior;
|
|
129
|
+
if (typeof behavior === "function") {
|
|
130
|
+
try {
|
|
131
|
+
return behavior(validateToolArguments(tool, toolCall));
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
return "block";
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return behavior ?? "block";
|
|
138
|
+
}
|
|
139
|
+
export async function runStructuredAdaptiveToolUse(toolCall, tool, signal, stream, canUseTool) {
|
|
140
|
+
const startedAt = Date.now();
|
|
141
|
+
stream.push({
|
|
142
|
+
type: "tool_execution_start",
|
|
143
|
+
toolCallId: toolCall.id,
|
|
144
|
+
toolName: toolCall.name,
|
|
145
|
+
args: toolCall.arguments,
|
|
146
|
+
});
|
|
147
|
+
let result;
|
|
148
|
+
let isError = false;
|
|
149
|
+
try {
|
|
150
|
+
if (!tool)
|
|
151
|
+
throw new ToolNotFoundError(toolCall.name);
|
|
152
|
+
const validatedArgs = validateToolArguments(tool, toolCall);
|
|
153
|
+
const validationMessage = await tool.validateInput?.(validatedArgs);
|
|
154
|
+
if (typeof validationMessage === "string" && validationMessage.trim()) {
|
|
155
|
+
throw new Error(validationMessage);
|
|
156
|
+
}
|
|
157
|
+
const permission = await canUseTool?.({
|
|
158
|
+
toolCallId: toolCall.id,
|
|
159
|
+
toolName: tool.name,
|
|
160
|
+
requestedToolName: toolCall.name,
|
|
161
|
+
input: validatedArgs,
|
|
162
|
+
rawInput: toolCall.arguments,
|
|
163
|
+
tool,
|
|
164
|
+
});
|
|
165
|
+
if (permission?.decision === "deny") {
|
|
166
|
+
const reason = permission.reason?.trim();
|
|
167
|
+
result = {
|
|
168
|
+
content: [
|
|
169
|
+
{ type: "text", text: reason ? `Permission denied: ${reason}` : `Permission denied for ${tool.name}` },
|
|
170
|
+
],
|
|
171
|
+
details: {
|
|
172
|
+
errorType: "permission_denied",
|
|
173
|
+
reason,
|
|
174
|
+
toolName: tool.name,
|
|
175
|
+
toolCallId: toolCall.id,
|
|
176
|
+
},
|
|
177
|
+
};
|
|
178
|
+
isError = true;
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
result = await tool.execute(toolCall.id, validatedArgs, signal, (partialResult) => {
|
|
182
|
+
stream.push({
|
|
183
|
+
type: "tool_execution_update",
|
|
184
|
+
toolCallId: toolCall.id,
|
|
185
|
+
toolName: toolCall.name,
|
|
186
|
+
args: toolCall.arguments,
|
|
187
|
+
partialResult,
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
result = enforceMaxResultSize(result, tool.maxResultSizeChars);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
catch (error) {
|
|
194
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
195
|
+
result = {
|
|
196
|
+
content: [{ type: "text", text: message }],
|
|
197
|
+
details: isPermissionDeniedMessage(message)
|
|
198
|
+
? {
|
|
199
|
+
errorType: "permission_denied",
|
|
200
|
+
reason: message,
|
|
201
|
+
toolName: tool?.name ?? toolCall.name,
|
|
202
|
+
toolCallId: toolCall.id,
|
|
203
|
+
}
|
|
204
|
+
: {},
|
|
205
|
+
};
|
|
206
|
+
isError = true;
|
|
207
|
+
}
|
|
208
|
+
stream.push({
|
|
209
|
+
type: "tool_execution_end",
|
|
210
|
+
toolCallId: toolCall.id,
|
|
211
|
+
toolName: toolCall.name,
|
|
212
|
+
result,
|
|
213
|
+
isError,
|
|
214
|
+
durationMs: Date.now() - startedAt,
|
|
215
|
+
});
|
|
216
|
+
const toolResult = {
|
|
217
|
+
role: "toolResult",
|
|
218
|
+
toolCallId: toolCall.id,
|
|
219
|
+
toolName: toolCall.name,
|
|
220
|
+
content: result.content,
|
|
221
|
+
details: result.details,
|
|
222
|
+
isError,
|
|
223
|
+
timestamp: Date.now(),
|
|
224
|
+
};
|
|
225
|
+
return {
|
|
226
|
+
toolResult,
|
|
227
|
+
contextMessages: result.contextMessages ?? [],
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
function isPermissionDeniedMessage(message) {
|
|
231
|
+
return /^Permission (denied|request was cancelled)/i.test(message.trim());
|
|
232
|
+
}
|
|
233
|
+
function extractPermissionDenials(toolResults) {
|
|
234
|
+
const denials = [];
|
|
235
|
+
for (const result of toolResults) {
|
|
236
|
+
const details = result.details;
|
|
237
|
+
if (!details || typeof details !== "object")
|
|
238
|
+
continue;
|
|
239
|
+
if (details.errorType !== "permission_denied")
|
|
240
|
+
continue;
|
|
241
|
+
const reason = details.reason;
|
|
242
|
+
denials.push({
|
|
243
|
+
toolCallId: result.toolCallId,
|
|
244
|
+
toolName: result.toolName,
|
|
245
|
+
reason: typeof reason === "string" && reason.length > 0 ? reason : undefined,
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
return denials;
|
|
249
|
+
}
|
|
250
|
+
function enforceMaxResultSize(result, maxResultSizeChars) {
|
|
251
|
+
if (!maxResultSizeChars || maxResultSizeChars <= 0)
|
|
252
|
+
return result;
|
|
253
|
+
let remaining = Math.floor(maxResultSizeChars);
|
|
254
|
+
let truncated = false;
|
|
255
|
+
const content = result.content.map((part) => {
|
|
256
|
+
if (part.type !== "text")
|
|
257
|
+
return part;
|
|
258
|
+
if (remaining <= 0) {
|
|
259
|
+
truncated = true;
|
|
260
|
+
return { ...part, text: "" };
|
|
261
|
+
}
|
|
262
|
+
if (part.text.length <= remaining) {
|
|
263
|
+
remaining -= part.text.length;
|
|
264
|
+
return part;
|
|
265
|
+
}
|
|
266
|
+
truncated = true;
|
|
267
|
+
const text = part.text.slice(0, remaining);
|
|
268
|
+
remaining = 0;
|
|
269
|
+
return { ...part, text };
|
|
270
|
+
});
|
|
271
|
+
if (!truncated)
|
|
272
|
+
return result;
|
|
273
|
+
const note = `\n\n[Tool result truncated to ${Math.floor(maxResultSizeChars)} characters.]`;
|
|
274
|
+
let lastTextIndex = -1;
|
|
275
|
+
for (let i = content.length - 1; i >= 0; i -= 1) {
|
|
276
|
+
if (content[i]?.type === "text") {
|
|
277
|
+
lastTextIndex = i;
|
|
278
|
+
break;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
if (lastTextIndex >= 0) {
|
|
282
|
+
const part = content[lastTextIndex];
|
|
283
|
+
content[lastTextIndex] = { ...part, text: `${part.text}${note}` };
|
|
284
|
+
}
|
|
285
|
+
else {
|
|
286
|
+
content.push({ type: "text", text: note.trimStart() });
|
|
287
|
+
}
|
|
288
|
+
return { ...result, content };
|
|
289
|
+
}
|
|
290
|
+
function skipStructuredAdaptiveToolCall(toolCall, stream) {
|
|
291
|
+
const startedAt = Date.now();
|
|
292
|
+
const result = {
|
|
293
|
+
content: [{ type: "text", text: "Skipped due to queued user message." }],
|
|
294
|
+
details: {},
|
|
295
|
+
};
|
|
296
|
+
stream.push({
|
|
297
|
+
type: "tool_execution_start",
|
|
298
|
+
toolCallId: toolCall.id,
|
|
299
|
+
toolName: toolCall.name,
|
|
300
|
+
args: toolCall.arguments,
|
|
301
|
+
});
|
|
302
|
+
stream.push({
|
|
303
|
+
type: "tool_execution_end",
|
|
304
|
+
toolCallId: toolCall.id,
|
|
305
|
+
toolName: toolCall.name,
|
|
306
|
+
result,
|
|
307
|
+
isError: true,
|
|
308
|
+
durationMs: Date.now() - startedAt,
|
|
309
|
+
});
|
|
310
|
+
return {
|
|
311
|
+
role: "toolResult",
|
|
312
|
+
toolCallId: toolCall.id,
|
|
313
|
+
toolName: toolCall.name,
|
|
314
|
+
content: result.content,
|
|
315
|
+
details: result.details,
|
|
316
|
+
isError: true,
|
|
317
|
+
timestamp: Date.now(),
|
|
318
|
+
};
|
|
319
|
+
}
|