@pencil-agent/nano-pencil 2.0.0-beta.2 → 2.0.0-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (179) hide show
  1. package/dist/build-meta.json +3 -3
  2. package/dist/node_modules/@pencil-agent/agent-core/dist/agent-loop-continuations.d.ts +17 -0
  3. package/dist/node_modules/@pencil-agent/agent-core/dist/agent-loop-continuations.js +60 -0
  4. package/dist/node_modules/@pencil-agent/agent-core/dist/agent-loop-stream-events.d.ts +19 -0
  5. package/dist/node_modules/@pencil-agent/agent-core/dist/agent-loop-stream-events.js +55 -0
  6. package/dist/node_modules/@pencil-agent/agent-core/dist/agent-loop-tool-results.d.ts +10 -0
  7. package/dist/node_modules/@pencil-agent/agent-core/dist/agent-loop-tool-results.js +137 -0
  8. package/dist/node_modules/@pencil-agent/agent-core/dist/agent-loop-tool-summaries.d.ts +22 -0
  9. package/dist/node_modules/@pencil-agent/agent-core/dist/agent-loop-tool-summaries.js +64 -0
  10. package/dist/node_modules/@pencil-agent/agent-core/dist/agent-loop.d.ts +26 -0
  11. package/dist/node_modules/@pencil-agent/agent-core/dist/agent-loop.js +913 -0
  12. package/dist/node_modules/@pencil-agent/agent-core/dist/agent-run-result.d.ts +9 -0
  13. package/dist/node_modules/@pencil-agent/agent-core/dist/agent-run-result.js +32 -0
  14. package/dist/node_modules/@pencil-agent/agent-core/dist/agent.d.ts +215 -0
  15. package/dist/node_modules/@pencil-agent/agent-core/dist/agent.js +522 -0
  16. package/dist/node_modules/@pencil-agent/agent-core/dist/errors.d.ts +62 -0
  17. package/dist/node_modules/@pencil-agent/agent-core/dist/errors.js +146 -0
  18. package/dist/node_modules/@pencil-agent/agent-core/dist/index.d.ts +14 -0
  19. package/dist/node_modules/@pencil-agent/agent-core/dist/index.js +19 -0
  20. package/dist/node_modules/@pencil-agent/agent-core/dist/proxy.d.ts +91 -0
  21. package/dist/node_modules/@pencil-agent/agent-core/dist/proxy.js +279 -0
  22. package/dist/node_modules/@pencil-agent/agent-core/dist/structured-adaptive-agent-loop.d.ts +15 -0
  23. package/dist/node_modules/@pencil-agent/agent-core/dist/structured-adaptive-agent-loop.js +625 -0
  24. package/dist/node_modules/@pencil-agent/agent-core/dist/structured-adaptive-streaming-tool-executor.d.ts +33 -0
  25. package/dist/node_modules/@pencil-agent/agent-core/dist/structured-adaptive-streaming-tool-executor.js +189 -0
  26. package/dist/node_modules/@pencil-agent/agent-core/dist/structured-adaptive-tool-orchestration.d.ts +35 -0
  27. package/dist/node_modules/@pencil-agent/agent-core/dist/structured-adaptive-tool-orchestration.js +319 -0
  28. package/dist/node_modules/@pencil-agent/agent-core/dist/types.d.ts +417 -0
  29. package/dist/node_modules/@pencil-agent/agent-core/dist/types.js +13 -0
  30. package/dist/node_modules/@pencil-agent/agent-core/package.json +28 -0
  31. package/dist/node_modules/@pencil-agent/ai/dist/api-registry.d.ts +27 -0
  32. package/dist/node_modules/@pencil-agent/ai/dist/api-registry.js +152 -0
  33. package/dist/node_modules/@pencil-agent/ai/dist/cli.d.ts +2 -0
  34. package/dist/node_modules/@pencil-agent/ai/dist/cli.js +121 -0
  35. package/dist/node_modules/@pencil-agent/ai/dist/config-path.d.ts +1 -0
  36. package/dist/node_modules/@pencil-agent/ai/dist/config-path.js +17 -0
  37. package/dist/node_modules/@pencil-agent/ai/dist/debug-logger.d.ts +94 -0
  38. package/dist/node_modules/@pencil-agent/ai/dist/debug-logger.js +218 -0
  39. package/dist/node_modules/@pencil-agent/ai/dist/env-api-keys.d.ts +8 -0
  40. package/dist/node_modules/@pencil-agent/ai/dist/env-api-keys.js +107 -0
  41. package/dist/node_modules/@pencil-agent/ai/dist/env.d.ts +7 -0
  42. package/dist/node_modules/@pencil-agent/ai/dist/env.js +7 -0
  43. package/dist/node_modules/@pencil-agent/ai/dist/events.d.ts +8 -0
  44. package/dist/node_modules/@pencil-agent/ai/dist/events.js +7 -0
  45. package/dist/node_modules/@pencil-agent/ai/dist/index.d.ts +27 -0
  46. package/dist/node_modules/@pencil-agent/ai/dist/index.js +20 -0
  47. package/dist/node_modules/@pencil-agent/ai/dist/json.d.ts +7 -0
  48. package/dist/node_modules/@pencil-agent/ai/dist/json.js +7 -0
  49. package/dist/node_modules/@pencil-agent/ai/dist/models.d.ts +31 -0
  50. package/dist/node_modules/@pencil-agent/ai/dist/models.generated.d.ts +15159 -0
  51. package/dist/node_modules/@pencil-agent/ai/dist/models.generated.js +14928 -0
  52. package/dist/node_modules/@pencil-agent/ai/dist/models.js +60 -0
  53. package/dist/node_modules/@pencil-agent/ai/dist/overflow.d.ts +7 -0
  54. package/dist/node_modules/@pencil-agent/ai/dist/overflow.js +7 -0
  55. package/dist/node_modules/@pencil-agent/ai/dist/providers/amazon-bedrock.d.ts +20 -0
  56. package/dist/node_modules/@pencil-agent/ai/dist/providers/amazon-bedrock.js +606 -0
  57. package/dist/node_modules/@pencil-agent/ai/dist/providers/anthropic.d.ts +38 -0
  58. package/dist/node_modules/@pencil-agent/ai/dist/providers/anthropic.js +737 -0
  59. package/dist/node_modules/@pencil-agent/ai/dist/providers/azure-openai-responses.d.ts +21 -0
  60. package/dist/node_modules/@pencil-agent/ai/dist/providers/azure-openai-responses.js +193 -0
  61. package/dist/node_modules/@pencil-agent/ai/dist/providers/github-copilot-headers.d.ts +13 -0
  62. package/dist/node_modules/@pencil-agent/ai/dist/providers/github-copilot-headers.js +34 -0
  63. package/dist/node_modules/@pencil-agent/ai/dist/providers/google-gemini-cli.d.ts +79 -0
  64. package/dist/node_modules/@pencil-agent/ai/dist/providers/google-gemini-cli.js +753 -0
  65. package/dist/node_modules/@pencil-agent/ai/dist/providers/google-shared.d.ts +70 -0
  66. package/dist/node_modules/@pencil-agent/ai/dist/providers/google-shared.js +311 -0
  67. package/dist/node_modules/@pencil-agent/ai/dist/providers/google-vertex.d.ts +20 -0
  68. package/dist/node_modules/@pencil-agent/ai/dist/providers/google-vertex.js +380 -0
  69. package/dist/node_modules/@pencil-agent/ai/dist/providers/google.d.ts +18 -0
  70. package/dist/node_modules/@pencil-agent/ai/dist/providers/google.js +360 -0
  71. package/dist/node_modules/@pencil-agent/ai/dist/providers/openai-codex-responses.d.ts +8 -0
  72. package/dist/node_modules/@pencil-agent/ai/dist/providers/openai-codex-responses.js +704 -0
  73. package/dist/node_modules/@pencil-agent/ai/dist/providers/openai-completions.d.ts +20 -0
  74. package/dist/node_modules/@pencil-agent/ai/dist/providers/openai-completions.js +870 -0
  75. package/dist/node_modules/@pencil-agent/ai/dist/providers/openai-responses-shared.d.ts +22 -0
  76. package/dist/node_modules/@pencil-agent/ai/dist/providers/openai-responses-shared.js +432 -0
  77. package/dist/node_modules/@pencil-agent/ai/dist/providers/openai-responses.d.ts +19 -0
  78. package/dist/node_modules/@pencil-agent/ai/dist/providers/openai-responses.js +207 -0
  79. package/dist/node_modules/@pencil-agent/ai/dist/providers/register-builtins.d.ts +8 -0
  80. package/dist/node_modules/@pencil-agent/ai/dist/providers/register-builtins.js +86 -0
  81. package/dist/node_modules/@pencil-agent/ai/dist/providers/simple-options.d.ts +13 -0
  82. package/dist/node_modules/@pencil-agent/ai/dist/providers/simple-options.js +40 -0
  83. package/dist/node_modules/@pencil-agent/ai/dist/providers/transform-messages.d.ts +13 -0
  84. package/dist/node_modules/@pencil-agent/ai/dist/providers/transform-messages.js +175 -0
  85. package/dist/node_modules/@pencil-agent/ai/dist/registry.d.ts +8 -0
  86. package/dist/node_modules/@pencil-agent/ai/dist/registry.js +8 -0
  87. package/dist/node_modules/@pencil-agent/ai/dist/schema.d.ts +10 -0
  88. package/dist/node_modules/@pencil-agent/ai/dist/schema.js +9 -0
  89. package/dist/node_modules/@pencil-agent/ai/dist/stream.d.ts +25 -0
  90. package/dist/node_modules/@pencil-agent/ai/dist/stream.js +324 -0
  91. package/dist/node_modules/@pencil-agent/ai/dist/types.d.ts +306 -0
  92. package/dist/node_modules/@pencil-agent/ai/dist/types.js +7 -0
  93. package/dist/node_modules/@pencil-agent/ai/dist/utils/event-stream-types.d.ts +12 -0
  94. package/dist/node_modules/@pencil-agent/ai/dist/utils/event-stream-types.js +7 -0
  95. package/dist/node_modules/@pencil-agent/ai/dist/utils/event-stream.d.ts +31 -0
  96. package/dist/node_modules/@pencil-agent/ai/dist/utils/event-stream.js +98 -0
  97. package/dist/node_modules/@pencil-agent/ai/dist/utils/http-proxy.d.ts +13 -0
  98. package/dist/node_modules/@pencil-agent/ai/dist/utils/http-proxy.js +20 -0
  99. package/dist/node_modules/@pencil-agent/ai/dist/utils/json-parse.d.ts +14 -0
  100. package/dist/node_modules/@pencil-agent/ai/dist/utils/json-parse.js +34 -0
  101. package/dist/node_modules/@pencil-agent/ai/dist/utils/oauth/anthropic.d.ts +22 -0
  102. package/dist/node_modules/@pencil-agent/ai/dist/utils/oauth/anthropic.js +109 -0
  103. package/dist/node_modules/@pencil-agent/ai/dist/utils/oauth/decode-credential.d.ts +12 -0
  104. package/dist/node_modules/@pencil-agent/ai/dist/utils/oauth/decode-credential.js +25 -0
  105. package/dist/node_modules/@pencil-agent/ai/dist/utils/oauth/github-copilot.d.ts +35 -0
  106. package/dist/node_modules/@pencil-agent/ai/dist/utils/oauth/github-copilot.js +286 -0
  107. package/dist/node_modules/@pencil-agent/ai/dist/utils/oauth/google-antigravity.d.ts +31 -0
  108. package/dist/node_modules/@pencil-agent/ai/dist/utils/oauth/google-antigravity.js +378 -0
  109. package/dist/node_modules/@pencil-agent/ai/dist/utils/oauth/google-gemini-cli.d.ts +31 -0
  110. package/dist/node_modules/@pencil-agent/ai/dist/utils/oauth/google-gemini-cli.js +483 -0
  111. package/dist/node_modules/@pencil-agent/ai/dist/utils/oauth/index.d.ts +60 -0
  112. package/dist/node_modules/@pencil-agent/ai/dist/utils/oauth/index.js +131 -0
  113. package/dist/node_modules/@pencil-agent/ai/dist/utils/oauth/openai-codex.d.ts +39 -0
  114. package/dist/node_modules/@pencil-agent/ai/dist/utils/oauth/openai-codex.js +385 -0
  115. package/dist/node_modules/@pencil-agent/ai/dist/utils/oauth/pkce.d.ts +18 -0
  116. package/dist/node_modules/@pencil-agent/ai/dist/utils/oauth/pkce.js +36 -0
  117. package/dist/node_modules/@pencil-agent/ai/dist/utils/oauth/types.d.ts +52 -0
  118. package/dist/node_modules/@pencil-agent/ai/dist/utils/oauth/types.js +7 -0
  119. package/dist/node_modules/@pencil-agent/ai/dist/utils/overflow.d.ts +57 -0
  120. package/dist/node_modules/@pencil-agent/ai/dist/utils/overflow.js +120 -0
  121. package/dist/node_modules/@pencil-agent/ai/dist/utils/sanitize-unicode.d.ts +16 -0
  122. package/dist/node_modules/@pencil-agent/ai/dist/utils/sanitize-unicode.js +20 -0
  123. package/dist/node_modules/@pencil-agent/ai/dist/utils/typebox-helpers.d.ts +22 -0
  124. package/dist/node_modules/@pencil-agent/ai/dist/utils/typebox-helpers.js +26 -0
  125. package/dist/node_modules/@pencil-agent/ai/dist/utils/validation.d.ts +23 -0
  126. package/dist/node_modules/@pencil-agent/ai/dist/utils/validation.js +78 -0
  127. package/dist/node_modules/@pencil-agent/ai/package.json +94 -0
  128. package/dist/node_modules/@pencil-agent/tui/dist/autocomplete.d.ts +62 -0
  129. package/dist/node_modules/@pencil-agent/tui/dist/autocomplete.js +624 -0
  130. package/dist/node_modules/@pencil-agent/tui/dist/components/box.d.ts +27 -0
  131. package/dist/node_modules/@pencil-agent/tui/dist/components/box.js +109 -0
  132. package/dist/node_modules/@pencil-agent/tui/dist/components/cancellable-loader.d.ts +27 -0
  133. package/dist/node_modules/@pencil-agent/tui/dist/components/cancellable-loader.js +40 -0
  134. package/dist/node_modules/@pencil-agent/tui/dist/components/editor.d.ts +218 -0
  135. package/dist/node_modules/@pencil-agent/tui/dist/components/editor.js +1697 -0
  136. package/dist/node_modules/@pencil-agent/tui/dist/components/image.d.ts +33 -0
  137. package/dist/node_modules/@pencil-agent/tui/dist/components/image.js +74 -0
  138. package/dist/node_modules/@pencil-agent/tui/dist/components/input.d.ts +42 -0
  139. package/dist/node_modules/@pencil-agent/tui/dist/components/input.js +438 -0
  140. package/dist/node_modules/@pencil-agent/tui/dist/components/loader.d.ts +26 -0
  141. package/dist/node_modules/@pencil-agent/tui/dist/components/loader.js +54 -0
  142. package/dist/node_modules/@pencil-agent/tui/dist/components/markdown.d.ts +100 -0
  143. package/dist/node_modules/@pencil-agent/tui/dist/components/markdown.js +634 -0
  144. package/dist/node_modules/@pencil-agent/tui/dist/components/select-list.d.ts +37 -0
  145. package/dist/node_modules/@pencil-agent/tui/dist/components/select-list.js +157 -0
  146. package/dist/node_modules/@pencil-agent/tui/dist/components/settings-list.d.ts +55 -0
  147. package/dist/node_modules/@pencil-agent/tui/dist/components/settings-list.js +190 -0
  148. package/dist/node_modules/@pencil-agent/tui/dist/components/spacer.d.ts +17 -0
  149. package/dist/node_modules/@pencil-agent/tui/dist/components/spacer.js +28 -0
  150. package/dist/node_modules/@pencil-agent/tui/dist/components/text.d.ts +24 -0
  151. package/dist/node_modules/@pencil-agent/tui/dist/components/text.js +94 -0
  152. package/dist/node_modules/@pencil-agent/tui/dist/components/truncated-text.d.ts +18 -0
  153. package/dist/node_modules/@pencil-agent/tui/dist/components/truncated-text.js +56 -0
  154. package/dist/node_modules/@pencil-agent/tui/dist/editor-component.d.ts +51 -0
  155. package/dist/node_modules/@pencil-agent/tui/dist/editor-component.js +7 -0
  156. package/dist/node_modules/@pencil-agent/tui/dist/fuzzy.d.ts +32 -0
  157. package/dist/node_modules/@pencil-agent/tui/dist/fuzzy.js +152 -0
  158. package/dist/node_modules/@pencil-agent/tui/dist/index.d.ts +28 -0
  159. package/dist/node_modules/@pencil-agent/tui/dist/index.js +37 -0
  160. package/dist/node_modules/@pencil-agent/tui/dist/keybindings.d.ts +44 -0
  161. package/dist/node_modules/@pencil-agent/tui/dist/keybindings.js +119 -0
  162. package/dist/node_modules/@pencil-agent/tui/dist/keys.d.ts +149 -0
  163. package/dist/node_modules/@pencil-agent/tui/dist/keys.js +948 -0
  164. package/dist/node_modules/@pencil-agent/tui/dist/kill-ring.d.ts +33 -0
  165. package/dist/node_modules/@pencil-agent/tui/dist/kill-ring.js +49 -0
  166. package/dist/node_modules/@pencil-agent/tui/dist/stdin-buffer.d.ts +38 -0
  167. package/dist/node_modules/@pencil-agent/tui/dist/stdin-buffer.js +307 -0
  168. package/dist/node_modules/@pencil-agent/tui/dist/terminal-image.d.ts +73 -0
  169. package/dist/node_modules/@pencil-agent/tui/dist/terminal-image.js +287 -0
  170. package/dist/node_modules/@pencil-agent/tui/dist/terminal.d.ts +86 -0
  171. package/dist/node_modules/@pencil-agent/tui/dist/terminal.js +266 -0
  172. package/dist/node_modules/@pencil-agent/tui/dist/tui.d.ts +219 -0
  173. package/dist/node_modules/@pencil-agent/tui/dist/tui.js +1001 -0
  174. package/dist/node_modules/@pencil-agent/tui/dist/undo-stack.d.ts +22 -0
  175. package/dist/node_modules/@pencil-agent/tui/dist/undo-stack.js +30 -0
  176. package/dist/node_modules/@pencil-agent/tui/dist/utils.d.ts +83 -0
  177. package/dist/node_modules/@pencil-agent/tui/dist/utils.js +811 -0
  178. package/dist/node_modules/@pencil-agent/tui/package.json +37 -0
  179. package/package.json +3 -2
@@ -0,0 +1,417 @@
1
+ /**
2
+ * [WHO]: AgentLoopFramework, AgentLoopTransition, AgentRunResult with transition history, AgentModelErrorRecoveryResult, AgentLoopConfig, CustomAgentMessages, AgentState, AgentToolResult, AgentTool, AgentToolConcurrencySafety, AgentToolInterruptBehavior
3
+ * [FROM]: No external dependencies
4
+ * [TO]: Consumed by core/lib/agent-core/src/index.ts
5
+ * [HERE]: core/lib/agent-core/src/types.ts -
6
+ */
7
+ import type { AssistantMessageEvent, ImageContent, Message, Model, SimpleStreamOptions, TextContent, Tool, ToolResultMessage, Usage } from "@pencil-agent/ai/types";
8
+ import type { streamSimple } from "@pencil-agent/ai/stream";
9
+ import type { Static, TSchema } from "@pencil-agent/ai/schema";
10
+ /** Stream function - can return sync or Promise for async config lookup */
11
+ export type StreamFn = (...args: Parameters<typeof streamSimple>) => ReturnType<typeof streamSimple> | Promise<ReturnType<typeof streamSimple>>;
12
+ export type AgentLoopFramework = "standard" | "weak-model-compatible";
13
+ export type AgentLoopFrameworkInput = AgentLoopFramework | "high-intelligence" | "low-intelligence" | "structured-adaptive";
14
+ export type AgentLoopTransition = {
15
+ reason: "start";
16
+ } | {
17
+ reason: "tool_result";
18
+ toolCallCount: number;
19
+ } | {
20
+ reason: "follow_up";
21
+ } | {
22
+ reason: "max_turns_reached";
23
+ maxTurns: number;
24
+ turnCount: number;
25
+ } | {
26
+ reason: "tool_call_limit_reached";
27
+ maxToolCalls: number;
28
+ requestedToolCalls: number;
29
+ toolCallCount: number;
30
+ } | {
31
+ reason: "stop_hook_limit_reached";
32
+ maxContinuations: number;
33
+ continuationCount: number;
34
+ } | {
35
+ reason: "max_output_tokens_recovery";
36
+ attempt: number;
37
+ } | {
38
+ reason: "stop_hook_blocking";
39
+ continuationCount: number;
40
+ } | {
41
+ reason: "model_error_recovery";
42
+ subtype: string;
43
+ attempt: number;
44
+ } | {
45
+ reason: "token_budget_continuation";
46
+ continuationCount: number;
47
+ outputTokens: number;
48
+ targetTokens: number;
49
+ };
50
+ export interface AgentRunResult {
51
+ stopReason: string;
52
+ loopFramework?: AgentLoopFramework;
53
+ loopPolicy?: AgentRunPolicy;
54
+ turnCount: number;
55
+ toolCallCount: number;
56
+ durationMs: number;
57
+ usage?: Usage;
58
+ permissionDenialCount?: number;
59
+ permissionDenials?: AgentToolPermissionDenial[];
60
+ transitions?: AgentLoopTransition[];
61
+ lastTransition?: AgentLoopTransition;
62
+ errorMessage?: string;
63
+ errorSubtype?: string;
64
+ }
65
+ export interface AgentRunPolicy {
66
+ maxModelErrorRecoveryAttempts?: number;
67
+ maxOutputTokenRecoveryAttempts?: number;
68
+ outputTokenBudget?: {
69
+ targetTokens: number;
70
+ thresholdPct?: number;
71
+ maxContinuations?: number;
72
+ };
73
+ maxStopHookContinuations?: number;
74
+ maxToolConcurrency?: number;
75
+ maxToolResultBatchSizeChars?: number;
76
+ maxTurnsPerPrompt?: number;
77
+ maxToolCallsPerPrompt?: number;
78
+ }
79
+ export declare function normalizeAgentLoopFramework(value: AgentLoopFrameworkInput | undefined): AgentLoopFramework | undefined;
80
+ export type AgentToolPermissionDecision = {
81
+ decision: "allow";
82
+ } | {
83
+ decision: "deny";
84
+ reason?: string;
85
+ };
86
+ export interface AgentToolPermissionDenial {
87
+ toolCallId: string;
88
+ toolName: string;
89
+ reason?: string;
90
+ }
91
+ export type AgentModelErrorRecoveryResult = {
92
+ action: "stop";
93
+ } | {
94
+ action: "retry";
95
+ messages: AgentMessage[];
96
+ transition?: AgentLoopTransition;
97
+ };
98
+ /**
99
+ * Configuration for the agent loop.
100
+ */
101
+ export interface AgentLoopConfig extends SimpleStreamOptions {
102
+ model: Model<any>;
103
+ loopFramework?: AgentLoopFrameworkInput;
104
+ /**
105
+ * Converts AgentMessage[] to LLM-compatible Message[] before each LLM call.
106
+ *
107
+ * Each AgentMessage must be converted to a UserMessage, AssistantMessage, or ToolResultMessage
108
+ * that the LLM can understand. AgentMessages that cannot be converted (e.g., UI-only notifications,
109
+ * status messages) should be filtered out.
110
+ *
111
+ * @example
112
+ * ```typescript
113
+ * convertToLlm: (messages) => messages.flatMap(m => {
114
+ * if (m.role === "custom") {
115
+ * // Convert custom message to user message
116
+ * return [{ role: "user", content: m.content, timestamp: m.timestamp }];
117
+ * }
118
+ * if (m.role === "notification") {
119
+ * // Filter out UI-only messages
120
+ * return [];
121
+ * }
122
+ * // Pass through standard LLM messages
123
+ * return [m];
124
+ * })
125
+ * ```
126
+ */
127
+ convertToLlm: (messages: AgentMessage[]) => Message[] | Promise<Message[]>;
128
+ /**
129
+ * Optional transform applied to the context before `convertToLlm`.
130
+ *
131
+ * Use this for operations that work at the AgentMessage level:
132
+ * - Context window management (pruning old messages)
133
+ * - Injecting context from external sources
134
+ *
135
+ * @example
136
+ * ```typescript
137
+ * transformContext: async (messages) => {
138
+ * if (estimateTokens(messages) > MAX_TOKENS) {
139
+ * return pruneOldMessages(messages);
140
+ * }
141
+ * return messages;
142
+ * }
143
+ * ```
144
+ */
145
+ transformContext?: (messages: AgentMessage[], signal?: AbortSignal) => Promise<AgentMessage[]>;
146
+ /**
147
+ * Resolves an API key dynamically for each LLM call.
148
+ *
149
+ * Useful for short-lived OAuth tokens (e.g., GitHub Copilot) that may expire
150
+ * during long-running tool execution phases.
151
+ */
152
+ getApiKey?: (provider: string) => Promise<string | undefined> | string | undefined;
153
+ /**
154
+ * Returns steering messages to inject into the conversation mid-run.
155
+ *
156
+ * Called after each tool execution to check for user interruptions.
157
+ * If messages are returned, remaining tool calls are skipped and
158
+ * these messages are added to the context before the next LLM call.
159
+ *
160
+ * Use this for "steering" the agent while it's working.
161
+ */
162
+ getSteeringMessages?: () => Promise<AgentMessage[]>;
163
+ /**
164
+ * Returns follow-up messages to process after the agent would otherwise stop.
165
+ *
166
+ * Called when the agent has no more tool calls and no steering messages.
167
+ * If messages are returned, they're added to the context and the agent
168
+ * continues with another turn.
169
+ *
170
+ * Use this for follow-up messages that should wait until the agent finishes.
171
+ */
172
+ getFollowUpMessages?: () => Promise<AgentMessage[]>;
173
+ /**
174
+ * Optional tool permission gate for agent loop tool execution.
175
+ *
176
+ * Called after schema/custom validation and before the tool executes.
177
+ * Return "deny" to feed a permission-denied tool_result back to the model
178
+ * without crashing the loop.
179
+ */
180
+ canUseTool?: (event: {
181
+ toolCallId: string;
182
+ toolName: string;
183
+ requestedToolName: string;
184
+ input: unknown;
185
+ rawInput: unknown;
186
+ tool: AgentTool<any>;
187
+ }) => Promise<AgentToolPermissionDecision> | AgentToolPermissionDecision;
188
+ /**
189
+ * Optional in-loop model error recovery hook.
190
+ *
191
+ * Hosts can use this to recover from context overflow or transient provider
192
+ * errors before the loop reaches agent_end. Return retry with a replacement
193
+ * AgentMessage context to make the next model call use recovered state.
194
+ */
195
+ recoverModelError?: (event: {
196
+ message: AgentMessage;
197
+ messages: AgentMessage[];
198
+ errorSubtype: string;
199
+ attempt: number;
200
+ }) => Promise<AgentModelErrorRecoveryResult> | AgentModelErrorRecoveryResult;
201
+ /**
202
+ * Optional non-blocking summary for completed tool batches.
203
+ *
204
+ * The loop starts this after a tool batch finishes. If the summary is
205
+ * already settled at the start of a later turn, it is emitted as a normal
206
+ * AgentMessage and included in that model request. If it is still pending,
207
+ * the model request proceeds without waiting.
208
+ */
209
+ createToolUseSummary?: (event: {
210
+ assistantMessage: AgentMessage;
211
+ toolResults: ToolResultMessage[];
212
+ contextMessages: AgentMessage[];
213
+ messages: AgentMessage[];
214
+ }) => AgentMessage | undefined | Promise<AgentMessage | undefined>;
215
+ /**
216
+ * Maximum model-error recovery retries for one prompt. Defaults to 1.
217
+ */
218
+ maxModelErrorRecoveryAttempts?: number;
219
+ /**
220
+ * Maximum assistant turns allowed for one prompt/continue loop.
221
+ *
222
+ * Prevents runaway model/tool/follow-up cycles from consuming unbounded
223
+ * tokens when the model keeps asking for tools or queued messages keep the
224
+ * loop alive.
225
+ */
226
+ maxTurnsPerPrompt?: number;
227
+ /**
228
+ * Maximum tool calls allowed for one prompt/continue loop.
229
+ *
230
+ * The loop stops before executing a batch that would exceed this limit and
231
+ * emits a controlled assistant error message.
232
+ */
233
+ maxToolCallsPerPrompt?: number;
234
+ /**
235
+ * Maximum concurrency for one batch of concurrency-safe tool calls in the
236
+ * weak-model-compatible loop. Defaults to 10.
237
+ */
238
+ maxToolConcurrency?: number;
239
+ /**
240
+ * Maximum combined text characters from one assistant tool-use batch that
241
+ * may be fed into the next model request.
242
+ *
243
+ * This aggregate guard complements per-tool maxResultSizeChars: it prevents
244
+ * several individually valid read/search results from flooding the next
245
+ * context turn. Loops preserve tool_result order and trim the largest
246
+ * successful results first.
247
+ */
248
+ maxToolResultBatchSizeChars?: number;
249
+ /**
250
+ * Maximum automatic continuations after a model stops because it hit its
251
+ * output-token limit. Defaults to 1.
252
+ */
253
+ maxOutputTokenRecoveryAttempts?: number;
254
+ /**
255
+ * Optional output-token budget target for long-form agent turns.
256
+ *
257
+ * If the assistant stops naturally before cumulative output reaches
258
+ * thresholdPct * targetTokens, the loop injects a meta continuation prompt.
259
+ * This is distinct from max-output-token recovery: it handles
260
+ * under-complete answers, not hard length stops.
261
+ */
262
+ outputTokenBudget?: {
263
+ targetTokens: number;
264
+ thresholdPct?: number;
265
+ maxContinuations?: number;
266
+ };
267
+ /**
268
+ * Optional stop hook. Called when the assistant would stop without tool
269
+ * calls. Return action "continue" with messages to force a
270
+ * correction/validation turn; return "stop" to allow completion.
271
+ */
272
+ runStopHooks?: (event: {
273
+ message: AgentMessage;
274
+ messages: AgentMessage[];
275
+ }) => Promise<StructuredAdaptiveStopHookResult> | StructuredAdaptiveStopHookResult;
276
+ /**
277
+ * Maximum stop-hook continuation turns for one prompt. Defaults to 3.
278
+ */
279
+ maxStopHookContinuations?: number;
280
+ }
281
+ export type StructuredAdaptiveStopHookResult = {
282
+ action: "stop";
283
+ } | {
284
+ action: "continue";
285
+ messages: AgentMessage[];
286
+ reason?: string;
287
+ };
288
+ /**
289
+ * Thinking/reasoning level for models that support it.
290
+ * Note: "xhigh" is only supported by OpenAI gpt-5.1-codex-max, gpt-5.2, gpt-5.2-codex, gpt-5.3, and gpt-5.3-codex models.
291
+ */
292
+ export type ThinkingLevel = "off" | "minimal" | "low" | "medium" | "high" | "xhigh";
293
+ /**
294
+ * Extensible interface for custom app messages.
295
+ * Apps can extend via declaration merging:
296
+ *
297
+ * @example
298
+ * ```typescript
299
+ * declare module "@pencil-agent/agent-core" {
300
+ * interface CustomAgentMessages {
301
+ * artifact: ArtifactMessage;
302
+ * notification: NotificationMessage;
303
+ * }
304
+ * }
305
+ * ```
306
+ */
307
+ export interface CustomAgentMessages {
308
+ }
309
+ /**
310
+ * AgentMessage: Union of LLM messages + custom messages.
311
+ * This abstraction allows apps to add custom message types while maintaining
312
+ * type safety and compatibility with the base LLM messages.
313
+ */
314
+ export type AgentMessage = Message | CustomAgentMessages[keyof CustomAgentMessages];
315
+ /**
316
+ * Agent state containing all configuration and conversation data.
317
+ */
318
+ export interface AgentState {
319
+ systemPrompt: string;
320
+ model: Model<any>;
321
+ thinkingLevel: ThinkingLevel;
322
+ tools: AgentTool<any>[];
323
+ messages: AgentMessage[];
324
+ isStreaming: boolean;
325
+ streamMessage: AgentMessage | null;
326
+ pendingToolCalls: Set<string>;
327
+ lastResult?: AgentRunResult;
328
+ error?: string;
329
+ }
330
+ export interface AgentToolResult<T> {
331
+ content: (TextContent | ImageContent)[];
332
+ details: T;
333
+ /**
334
+ * Optional messages appended after the corresponding tool_result messages.
335
+ * Use this for tool-generated attachments or context updates that should not
336
+ * interrupt assistant tool_use -> tool_result pairing.
337
+ */
338
+ contextMessages?: AgentMessage[];
339
+ }
340
+ export type AgentToolUpdateCallback<T = any> = (partialResult: AgentToolResult<T>) => void;
341
+ export type AgentToolConcurrencySafety<TParameters extends TSchema = TSchema> = boolean | ((params: Static<TParameters>) => boolean);
342
+ export type AgentToolInterruptBehavior<TParameters extends TSchema = TSchema> = "cancel" | "block" | ((params: Static<TParameters>) => "cancel" | "block");
343
+ export interface AgentTool<TParameters extends TSchema = TSchema, TDetails = any> extends Tool<TParameters> {
344
+ label: string;
345
+ /** Alternative model-facing names accepted for transcript/tool compatibility. */
346
+ aliases?: string[];
347
+ /**
348
+ * Whether the tool can safely run alongside other concurrency-safe tools.
349
+ * The weak-model-compatible loop uses this to batch read-only work while keeping
350
+ * stateful tools such as edit/write/bash serialized.
351
+ */
352
+ isConcurrencySafe?: AgentToolConcurrencySafety<TParameters>;
353
+ interruptBehavior?: AgentToolInterruptBehavior<TParameters>;
354
+ /** Optional semantic validation after schema validation and before execute. */
355
+ validateInput?: (params: Static<TParameters>) => void | string | Promise<void | string>;
356
+ /** Optional maximum text result size enforced by agent loop tool orchestration. */
357
+ maxResultSizeChars?: number;
358
+ execute: (toolCallId: string, params: Static<TParameters>, signal?: AbortSignal, onUpdate?: AgentToolUpdateCallback<TDetails>) => Promise<AgentToolResult<TDetails>>;
359
+ }
360
+ export interface AgentContext {
361
+ systemPrompt: string;
362
+ messages: AgentMessage[];
363
+ tools?: AgentTool<any>[];
364
+ }
365
+ /**
366
+ * Events emitted by the Agent for UI updates.
367
+ * These events provide fine-grained lifecycle information for messages, turns, and tool executions.
368
+ */
369
+ export type AgentEvent = {
370
+ type: "agent_start";
371
+ } | {
372
+ type: "agent_end";
373
+ messages: AgentMessage[];
374
+ } | ({
375
+ type: "agent_result";
376
+ } & AgentRunResult) | {
377
+ type: "stream_request_start";
378
+ model: string;
379
+ provider: string;
380
+ api: string;
381
+ messageCount: number;
382
+ maxTokens?: number;
383
+ } | {
384
+ type: "turn_start";
385
+ } | {
386
+ type: "turn_end";
387
+ message: AgentMessage;
388
+ toolResults: ToolResultMessage[];
389
+ } | {
390
+ type: "message_start";
391
+ message: AgentMessage;
392
+ } | {
393
+ type: "message_update";
394
+ message: AgentMessage;
395
+ assistantMessageEvent: AssistantMessageEvent;
396
+ } | {
397
+ type: "message_end";
398
+ message: AgentMessage;
399
+ } | {
400
+ type: "tool_execution_start";
401
+ toolCallId: string;
402
+ toolName: string;
403
+ args: any;
404
+ } | {
405
+ type: "tool_execution_update";
406
+ toolCallId: string;
407
+ toolName: string;
408
+ args: any;
409
+ partialResult: any;
410
+ } | {
411
+ type: "tool_execution_end";
412
+ toolCallId: string;
413
+ toolName: string;
414
+ result: any;
415
+ isError: boolean;
416
+ durationMs?: number;
417
+ };
@@ -0,0 +1,13 @@
1
+ /**
2
+ * [WHO]: AgentLoopFramework, AgentLoopTransition, AgentRunResult with transition history, AgentModelErrorRecoveryResult, AgentLoopConfig, CustomAgentMessages, AgentState, AgentToolResult, AgentTool, AgentToolConcurrencySafety, AgentToolInterruptBehavior
3
+ * [FROM]: No external dependencies
4
+ * [TO]: Consumed by core/lib/agent-core/src/index.ts
5
+ * [HERE]: core/lib/agent-core/src/types.ts -
6
+ */
7
+ export function normalizeAgentLoopFramework(value) {
8
+ if (value === "high-intelligence")
9
+ return "standard";
10
+ if (value === "low-intelligence" || value === "structured-adaptive")
11
+ return "weak-model-compatible";
12
+ return value;
13
+ }
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "@pencil-agent/agent-core",
3
+ "version": "0.0.1",
4
+ "description": "General-purpose agent with transport abstraction, state management, and attachment support",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "dependencies": {
9
+ "@pencil-agent/ai": "0.0.1"
10
+ },
11
+ "keywords": [
12
+ "ai",
13
+ "agent",
14
+ "llm",
15
+ "transport",
16
+ "state-management",
17
+ "pencil-agent"
18
+ ],
19
+ "author": "nanoPencil Team",
20
+ "license": "GPL-3.0",
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "git+https://github.com/O-Pencil/nanoPencil.git"
24
+ },
25
+ "engines": {
26
+ "node": ">=20.0.0"
27
+ }
28
+ }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * [WHO]: ApiProvider, registerApiProvider, registerApiProviderLoader, getApiProvider, ensureApiProvider, reset helpers
3
+ * [FROM]: Depends on core AI stream/model types for provider contracts
4
+ * [TO]: Consumed by core/lib/ai/src/stream.ts and providers/register-builtins.ts for provider dispatch
5
+ * [HERE]: core/lib/ai/src/api-registry.ts - provider registry plus runtime lazy-loader registry
6
+ */
7
+ import type { Api, AssistantMessageEventStreamContract, Context, Model, SimpleStreamOptions, StreamFunction, StreamOptions } from "./types.js";
8
+ export type ApiStreamFunction = (model: Model<Api>, context: Context, options?: StreamOptions) => AssistantMessageEventStreamContract;
9
+ export type ApiStreamSimpleFunction = (model: Model<Api>, context: Context, options?: SimpleStreamOptions) => AssistantMessageEventStreamContract;
10
+ export interface ApiProvider<TApi extends Api = Api, TOptions extends StreamOptions = StreamOptions> {
11
+ api: TApi;
12
+ stream: StreamFunction<TApi, TOptions>;
13
+ streamSimple: StreamFunction<TApi, SimpleStreamOptions>;
14
+ }
15
+ export interface ApiProviderInternal {
16
+ api: Api;
17
+ stream: ApiStreamFunction;
18
+ streamSimple: ApiStreamSimpleFunction;
19
+ }
20
+ export type ApiProviderLoader<TApi extends Api = Api, TOptions extends StreamOptions = StreamOptions> = () => Promise<ApiProvider<TApi, TOptions>>;
21
+ export declare function registerApiProvider<TApi extends Api, TOptions extends StreamOptions>(provider: ApiProvider<TApi, TOptions>, sourceId?: string): void;
22
+ export declare function registerApiProviderLoader<TApi extends Api, TOptions extends StreamOptions>(api: TApi, loader: ApiProviderLoader<TApi, TOptions>, sourceId?: string): void;
23
+ export declare function getApiProvider(api: Api): ApiProviderInternal | undefined;
24
+ export declare function ensureApiProvider(api: Api): Promise<ApiProviderInternal | undefined>;
25
+ export declare function getApiProviders(): ApiProviderInternal[];
26
+ export declare function unregisterApiProviders(sourceId: string): void;
27
+ export declare function clearApiProviders(): void;
@@ -0,0 +1,152 @@
1
+ /**
2
+ * [WHO]: ApiProvider, registerApiProvider, registerApiProviderLoader, getApiProvider, ensureApiProvider, reset helpers
3
+ * [FROM]: Depends on core AI stream/model types for provider contracts
4
+ * [TO]: Consumed by core/lib/ai/src/stream.ts and providers/register-builtins.ts for provider dispatch
5
+ * [HERE]: core/lib/ai/src/api-registry.ts - provider registry plus runtime lazy-loader registry
6
+ */
7
+ import { AssistantMessageEventStream } from "./utils/event-stream.js";
8
+ const apiProviderRegistry = new Map();
9
+ const apiProviderLoaders = new Map();
10
+ function wrapStream(api, stream) {
11
+ return (model, context, options) => {
12
+ if (model.api !== api) {
13
+ throw new Error(`Mismatched api: ${model.api} expected ${api}`);
14
+ }
15
+ return stream(model, context, options);
16
+ };
17
+ }
18
+ function wrapStreamSimple(api, streamSimple) {
19
+ return (model, context, options) => {
20
+ if (model.api !== api) {
21
+ throw new Error(`Mismatched api: ${model.api} expected ${api}`);
22
+ }
23
+ return streamSimple(model, context, options);
24
+ };
25
+ }
26
+ function emptyUsage() {
27
+ return {
28
+ input: 0,
29
+ output: 0,
30
+ cacheRead: 0,
31
+ cacheWrite: 0,
32
+ totalTokens: 0,
33
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
34
+ };
35
+ }
36
+ function getErrorMessage(error) {
37
+ if (error instanceof Error)
38
+ return error.message;
39
+ if (typeof error === "string")
40
+ return error;
41
+ return JSON.stringify(error) ?? String(error);
42
+ }
43
+ function createProviderLoadErrorMessage(model, error) {
44
+ return {
45
+ role: "assistant",
46
+ content: [],
47
+ api: model.api,
48
+ provider: model.provider,
49
+ model: model.id,
50
+ stopReason: "error",
51
+ errorMessage: getErrorMessage(error),
52
+ usage: emptyUsage(),
53
+ timestamp: Date.now(),
54
+ };
55
+ }
56
+ function createMissingProviderResultMessage(model) {
57
+ return createProviderLoadErrorMessage(model, new Error("Provider stream ended without a final assistant message"));
58
+ }
59
+ function createLazyProvider(api) {
60
+ return {
61
+ api,
62
+ stream: (model, context, options) => {
63
+ const stream = new AssistantMessageEventStream();
64
+ void pipeLazyProviderStream(api, model, context, options, stream, "stream");
65
+ return stream;
66
+ },
67
+ streamSimple: (model, context, options) => {
68
+ const stream = new AssistantMessageEventStream();
69
+ void pipeLazyProviderStream(api, model, context, options, stream, "streamSimple");
70
+ return stream;
71
+ },
72
+ };
73
+ }
74
+ async function pipeLazyProviderStream(api, model, context, options, output, method) {
75
+ try {
76
+ const provider = await ensureApiProvider(api);
77
+ if (!provider) {
78
+ throw new Error(`No API provider registered for api: ${api}`);
79
+ }
80
+ const source = method === "stream"
81
+ ? provider.stream(model, context, options)
82
+ : provider.streamSimple(model, context, options);
83
+ for await (const event of source) {
84
+ output.push(event);
85
+ }
86
+ if (!source.resultIfResolved()) {
87
+ output.push({ type: "error", reason: "error", error: createMissingProviderResultMessage(model) });
88
+ }
89
+ }
90
+ catch (error) {
91
+ output.push({ type: "error", reason: "error", error: createProviderLoadErrorMessage(model, error) });
92
+ }
93
+ }
94
+ export function registerApiProvider(provider, sourceId) {
95
+ apiProviderRegistry.set(provider.api, {
96
+ provider: {
97
+ api: provider.api,
98
+ stream: wrapStream(provider.api, provider.stream),
99
+ streamSimple: wrapStreamSimple(provider.api, provider.streamSimple),
100
+ },
101
+ sourceId,
102
+ });
103
+ }
104
+ export function registerApiProviderLoader(api, loader, sourceId) {
105
+ apiProviderLoaders.set(api, { loader, sourceId });
106
+ apiProviderRegistry.set(api, {
107
+ provider: createLazyProvider(api),
108
+ sourceId,
109
+ lazy: true,
110
+ });
111
+ }
112
+ export function getApiProvider(api) {
113
+ return apiProviderRegistry.get(api)?.provider;
114
+ }
115
+ export async function ensureApiProvider(api) {
116
+ const entry = apiProviderRegistry.get(api);
117
+ if (entry && !entry.lazy)
118
+ return entry.provider;
119
+ const loader = apiProviderLoaders.get(api);
120
+ if (!loader)
121
+ return entry?.provider;
122
+ loader.pending ??= loader
123
+ .loader()
124
+ .then((provider) => {
125
+ registerApiProvider(provider, loader.sourceId);
126
+ return getApiProvider(api);
127
+ })
128
+ .finally(() => {
129
+ loader.pending = undefined;
130
+ });
131
+ await loader.pending;
132
+ return getApiProvider(api);
133
+ }
134
+ export function getApiProviders() {
135
+ return Array.from(apiProviderRegistry.values(), (entry) => entry.provider);
136
+ }
137
+ export function unregisterApiProviders(sourceId) {
138
+ for (const [api, entry] of apiProviderRegistry.entries()) {
139
+ if (entry.sourceId === sourceId) {
140
+ apiProviderRegistry.delete(api);
141
+ }
142
+ }
143
+ for (const [api, entry] of apiProviderLoaders.entries()) {
144
+ if (entry.sourceId === sourceId) {
145
+ apiProviderLoaders.delete(api);
146
+ }
147
+ }
148
+ }
149
+ export function clearApiProviders() {
150
+ apiProviderRegistry.clear();
151
+ apiProviderLoaders.clear();
152
+ }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};