@a5c-ai/genty-core 5.1.1-staging.5ad08884fb61

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 (170) hide show
  1. package/README.md +306 -0
  2. package/dist/agenticTools/background/state.d.ts +7 -0
  3. package/dist/agenticTools/background/state.d.ts.map +1 -0
  4. package/dist/agenticTools/background/state.js +11 -0
  5. package/dist/agenticTools/background/tools.d.ts +3 -0
  6. package/dist/agenticTools/background/tools.d.ts.map +1 -0
  7. package/dist/agenticTools/background/tools.js +37 -0
  8. package/dist/agenticTools/browser/tool.d.ts +3 -0
  9. package/dist/agenticTools/browser/tool.d.ts.map +1 -0
  10. package/dist/agenticTools/browser/tool.js +64 -0
  11. package/dist/agenticTools/config/state.d.ts +10 -0
  12. package/dist/agenticTools/config/state.d.ts.map +1 -0
  13. package/dist/agenticTools/config/state.js +39 -0
  14. package/dist/agenticTools/config/state.test.d.ts +2 -0
  15. package/dist/agenticTools/config/state.test.d.ts.map +1 -0
  16. package/dist/agenticTools/config/state.test.js +23 -0
  17. package/dist/agenticTools/config/tool.d.ts +3 -0
  18. package/dist/agenticTools/config/tool.d.ts.map +1 -0
  19. package/dist/agenticTools/config/tool.js +87 -0
  20. package/dist/agenticTools/discovery/tools.d.ts +3 -0
  21. package/dist/agenticTools/discovery/tools.d.ts.map +1 -0
  22. package/dist/agenticTools/discovery/tools.js +73 -0
  23. package/dist/agenticTools/index.d.ts +5 -0
  24. package/dist/agenticTools/index.d.ts.map +1 -0
  25. package/dist/agenticTools/index.js +63 -0
  26. package/dist/agenticTools/shared/paths.d.ts +5 -0
  27. package/dist/agenticTools/shared/paths.d.ts.map +1 -0
  28. package/dist/agenticTools/shared/paths.js +117 -0
  29. package/dist/agenticTools/shared/process.d.ts +23 -0
  30. package/dist/agenticTools/shared/process.d.ts.map +1 -0
  31. package/dist/agenticTools/shared/process.js +142 -0
  32. package/dist/agenticTools/shared/results.d.ts +9 -0
  33. package/dist/agenticTools/shared/results.d.ts.map +1 -0
  34. package/dist/agenticTools/shared/results.js +52 -0
  35. package/dist/agenticTools/tools/code.d.ts +3 -0
  36. package/dist/agenticTools/tools/code.d.ts.map +1 -0
  37. package/dist/agenticTools/tools/code.js +467 -0
  38. package/dist/agenticTools/tools/delegation.d.ts +3 -0
  39. package/dist/agenticTools/tools/delegation.d.ts.map +1 -0
  40. package/dist/agenticTools/tools/delegation.js +207 -0
  41. package/dist/agenticTools/tools/execution.d.ts +3 -0
  42. package/dist/agenticTools/tools/execution.d.ts.map +1 -0
  43. package/dist/agenticTools/tools/execution.js +237 -0
  44. package/dist/agenticTools/tools/fileSystem.d.ts +3 -0
  45. package/dist/agenticTools/tools/fileSystem.d.ts.map +1 -0
  46. package/dist/agenticTools/tools/fileSystem.js +233 -0
  47. package/dist/agenticTools/tools/programmaticToolCalling.d.ts +4 -0
  48. package/dist/agenticTools/tools/programmaticToolCalling.d.ts.map +1 -0
  49. package/dist/agenticTools/tools/programmaticToolCalling.js +155 -0
  50. package/dist/agenticTools/types.d.ts +3 -0
  51. package/dist/agenticTools/types.d.ts.map +1 -0
  52. package/dist/agenticTools/types.js +5 -0
  53. package/dist/agenticTools/web/content.d.ts +3 -0
  54. package/dist/agenticTools/web/content.d.ts.map +1 -0
  55. package/dist/agenticTools/web/content.js +54 -0
  56. package/dist/agenticTools/web/searchHelpers.d.ts +8 -0
  57. package/dist/agenticTools/web/searchHelpers.d.ts.map +1 -0
  58. package/dist/agenticTools/web/searchHelpers.js +50 -0
  59. package/dist/agenticTools/web/tools.d.ts +3 -0
  60. package/dist/agenticTools/web/tools.d.ts.map +1 -0
  61. package/dist/agenticTools/web/tools.js +119 -0
  62. package/dist/backgroundProcessRegistry.d.ts +7 -0
  63. package/dist/backgroundProcessRegistry.d.ts.map +1 -0
  64. package/dist/backgroundProcessRegistry.js +10 -0
  65. package/dist/context/index.d.ts +5 -0
  66. package/dist/context/index.d.ts.map +1 -0
  67. package/dist/context/index.js +12 -0
  68. package/dist/context/manager.d.ts +44 -0
  69. package/dist/context/manager.d.ts.map +1 -0
  70. package/dist/context/manager.js +115 -0
  71. package/dist/context/strategies/index.d.ts +4 -0
  72. package/dist/context/strategies/index.d.ts.map +1 -0
  73. package/dist/context/strategies/index.js +9 -0
  74. package/dist/context/strategies/priority.d.ts +29 -0
  75. package/dist/context/strategies/priority.d.ts.map +1 -0
  76. package/dist/context/strategies/priority.js +58 -0
  77. package/dist/context/strategies/sliding.d.ts +27 -0
  78. package/dist/context/strategies/sliding.d.ts.map +1 -0
  79. package/dist/context/strategies/sliding.js +62 -0
  80. package/dist/context/strategies/summary.d.ts +41 -0
  81. package/dist/context/strategies/summary.d.ts.map +1 -0
  82. package/dist/context/strategies/summary.js +75 -0
  83. package/dist/context/token-estimator.d.ts +25 -0
  84. package/dist/context/token-estimator.d.ts.map +1 -0
  85. package/dist/context/token-estimator.js +53 -0
  86. package/dist/context/types.d.ts +137 -0
  87. package/dist/context/types.d.ts.map +1 -0
  88. package/dist/context/types.js +9 -0
  89. package/dist/deferredToolRegistry.d.ts +85 -0
  90. package/dist/deferredToolRegistry.d.ts.map +1 -0
  91. package/dist/deferredToolRegistry.js +150 -0
  92. package/dist/deferredToolRegistry.test.d.ts +2 -0
  93. package/dist/deferredToolRegistry.test.d.ts.map +1 -0
  94. package/dist/deferredToolRegistry.test.js +92 -0
  95. package/dist/index.d.ts +15 -0
  96. package/dist/index.d.ts.map +1 -0
  97. package/dist/index.js +42 -0
  98. package/dist/loop/agent-loop.d.ts +55 -0
  99. package/dist/loop/agent-loop.d.ts.map +1 -0
  100. package/dist/loop/agent-loop.js +303 -0
  101. package/dist/loop/index.d.ts +6 -0
  102. package/dist/loop/index.d.ts.map +1 -0
  103. package/dist/loop/index.js +11 -0
  104. package/dist/loop/strategies/concurrent.d.ts +41 -0
  105. package/dist/loop/strategies/concurrent.d.ts.map +1 -0
  106. package/dist/loop/strategies/concurrent.js +86 -0
  107. package/dist/loop/strategies/group-chat.d.ts +44 -0
  108. package/dist/loop/strategies/group-chat.d.ts.map +1 -0
  109. package/dist/loop/strategies/group-chat.js +121 -0
  110. package/dist/loop/strategies/handoff.d.ts +50 -0
  111. package/dist/loop/strategies/handoff.d.ts.map +1 -0
  112. package/dist/loop/strategies/handoff.js +112 -0
  113. package/dist/loop/strategies/index.d.ts +9 -0
  114. package/dist/loop/strategies/index.d.ts.map +1 -0
  115. package/dist/loop/strategies/index.js +11 -0
  116. package/dist/loop/strategies/sequential.d.ts +19 -0
  117. package/dist/loop/strategies/sequential.d.ts.map +1 -0
  118. package/dist/loop/strategies/sequential.js +29 -0
  119. package/dist/loop/types.d.ts +144 -0
  120. package/dist/loop/types.d.ts.map +1 -0
  121. package/dist/loop/types.js +9 -0
  122. package/dist/session.d.ts +41 -0
  123. package/dist/session.d.ts.map +1 -0
  124. package/dist/session.js +838 -0
  125. package/dist/session.test.d.ts +2 -0
  126. package/dist/session.test.d.ts.map +1 -0
  127. package/dist/session.test.js +665 -0
  128. package/dist/subagent/index.d.ts +6 -0
  129. package/dist/subagent/index.d.ts.map +1 -0
  130. package/dist/subagent/index.js +7 -0
  131. package/dist/subagent/invoker.d.ts +34 -0
  132. package/dist/subagent/invoker.d.ts.map +1 -0
  133. package/dist/subagent/invoker.js +132 -0
  134. package/dist/subagent/oversight.d.ts +43 -0
  135. package/dist/subagent/oversight.d.ts.map +1 -0
  136. package/dist/subagent/oversight.js +63 -0
  137. package/dist/subagent/types.d.ts +141 -0
  138. package/dist/subagent/types.d.ts.map +1 -0
  139. package/dist/subagent/types.js +9 -0
  140. package/dist/synthesis/index.d.ts +4 -0
  141. package/dist/synthesis/index.d.ts.map +1 -0
  142. package/dist/synthesis/index.js +9 -0
  143. package/dist/synthesis/strategies/index.d.ts +4 -0
  144. package/dist/synthesis/strategies/index.d.ts.map +1 -0
  145. package/dist/synthesis/strategies/index.js +9 -0
  146. package/dist/synthesis/strategies/merge.d.ts +18 -0
  147. package/dist/synthesis/strategies/merge.d.ts.map +1 -0
  148. package/dist/synthesis/strategies/merge.js +104 -0
  149. package/dist/synthesis/strategies/rank.d.ts +25 -0
  150. package/dist/synthesis/strategies/rank.d.ts.map +1 -0
  151. package/dist/synthesis/strategies/rank.js +51 -0
  152. package/dist/synthesis/strategies/vote.d.ts +17 -0
  153. package/dist/synthesis/strategies/vote.d.ts.map +1 -0
  154. package/dist/synthesis/strategies/vote.js +59 -0
  155. package/dist/synthesis/synthesizer.d.ts +25 -0
  156. package/dist/synthesis/synthesizer.d.ts.map +1 -0
  157. package/dist/synthesis/synthesizer.js +38 -0
  158. package/dist/synthesis/types.d.ts +96 -0
  159. package/dist/synthesis/types.d.ts.map +1 -0
  160. package/dist/synthesis/types.js +8 -0
  161. package/dist/tools.d.ts +9 -0
  162. package/dist/tools.d.ts.map +1 -0
  163. package/dist/tools.js +18 -0
  164. package/dist/tools.test.d.ts +2 -0
  165. package/dist/tools.test.d.ts.map +1 -0
  166. package/dist/tools.test.js +862 -0
  167. package/dist/types.d.ts +275 -0
  168. package/dist/types.d.ts.map +1 -0
  169. package/dist/types.js +35 -0
  170. package/package.json +57 -0
package/README.md ADDED
@@ -0,0 +1,306 @@
1
+ # @a5c-ai/genty-core
2
+
3
+ genty core programmatic session wrapper and agentic tool surface for Babysitter runtime consumers.
4
+
5
+ <!-- docs-status:start -->
6
+ > Status: Public advanced/runtime package.
7
+ > Canonical docs home: [Package and Plugin Docs Map](../../docs/package-and-plugin-map.md).
8
+ > This README defines the package contract for runtime consumers and published dependents such as `@a5c-ai/genty-platform`.
9
+ <!-- docs-status:end -->
10
+
11
+ ## Package role
12
+
13
+ `@a5c-ai/genty-core` sits between `@a5c-ai/genty-platform`, `@a5c-ai/adapters`, and `@a5c-ai/babysitter-sdk`:
14
+
15
+ - `createAgentCoreSession()` wraps an `@a5c-ai/adapters` client for in-process prompt execution.
16
+ - `createAgentCoreToolDefinitions()` assembles the built-in Babysitter-flavored tool surface that host runtimes can inject into planning, resume, or delegated-task flows.
17
+ - `@a5c-ai/genty-platform` re-exports these APIs from `src/harness/index.ts`, uses `createAgentCoreSession()` for direct `genty-core` harness invocation in `src/harness/invoker.ts`, and injects tool definitions into plan-process and resume-run flows.
18
+ - `@a5c-ai/babysitter-sdk` still owns run directories, journals, task/effect lifecycle, and config defaults. `genty-core` does not replace the SDK orchestration layer.
19
+
20
+ This package is published as a runtime dependency surface for higher-level Babysitter runtimes. It is still an advanced/operator-facing building block rather than the primary entrypoint for new users.
21
+
22
+ ## Root exports
23
+
24
+ The package root exports the runtime surface assembled from `src/index.ts` and `src/tools.ts`:
25
+
26
+ ```ts
27
+ import {
28
+ AGENT_CORE_TOOL_NAMES,
29
+ AgentCoreSessionHandle,
30
+ DeferredToolRegistry,
31
+ createAgentCoreSession,
32
+ createAgentCoreToolDefinitions,
33
+ disposeAgentCoreToolDefinitions,
34
+ extractTextFromHtml,
35
+ filterByRelevance,
36
+ parseSearchResults,
37
+ resetRunScopedConfig,
38
+ stripHtmlTags,
39
+ type AgentCoreEventListener,
40
+ type AgentCoreImageBase64PromptPart,
41
+ type AgentCoreImageUrlPromptPart,
42
+ type AgentCoreJsonSchema,
43
+ type AgentCoreOutputFormat,
44
+ type AgentCorePromptInput,
45
+ type AgentCorePromptOptions,
46
+ type AgentCorePromptPart,
47
+ type AgentCorePromptResult,
48
+ type AgentCoreSessionEvent,
49
+ type AgentCoreSessionOptions,
50
+ type AgentCoreStructuredOutputOptions,
51
+ type AgentCoreTextPromptPart,
52
+ type AgentCoreToolOptions,
53
+ type CustomToolDefinition,
54
+ type ToolResult,
55
+ } from "@a5c-ai/genty-core";
56
+ ```
57
+
58
+ Key exports:
59
+
60
+ - `createAgentCoreSession(options)` / `AgentCoreSessionHandle`: programmatic session API backed by `@a5c-ai/adapters`.
61
+ - `createAgentCoreToolDefinitions(options)` / `disposeAgentCoreToolDefinitions(definitions)`: built-in tool-definition assembly and teardown.
62
+ - `DeferredToolRegistry`: lazy registry for searchable/fetchable external tool schemas.
63
+ - `AGENT_CORE_TOOL_NAMES`: canonical bundled tool name list.
64
+ - `AgenticToolOptions` and `AGENTIC_TOOL_NAMES`: compatibility aliases for older host integrations.
65
+ - `resetRunScopedConfig()`: clears run-scoped state used by the `config` tool.
66
+ - `parseSearchResults()`, `stripHtmlTags()`, `extractTextFromHtml()`, `filterByRelevance()`: helper exports used by web/search integrations.
67
+
68
+ ## Session API
69
+
70
+ `createAgentCoreSession()` returns an `AgentCoreSessionHandle` that wraps a shared `@a5c-ai/adapters` client with built-in adapters registered once per process.
71
+
72
+ Core handle methods:
73
+
74
+ - `initialize()`: currently a no-op placeholder for compatibility.
75
+ - `prompt(text, timeout?)`: starts a run, streams events to subscribers, and returns `{ output, duration, success, exitCode }`.
76
+ - `prompt(input, options?)`: accepts text or multimodal prompt parts and optional structured-output settings.
77
+ - `steer(text)`: sends immediate steering text while a prompt is active, or queues it for the next prompt.
78
+ - `followUp(text)`: queues a post-response follow-up when streaming, or appends it to the next prompt when idle.
79
+ - `getHistory()`: returns a defensive copy of persisted user/assistant turns for the session handle.
80
+ - `clearHistory()`: clears persisted user/assistant turns without changing listeners, options, or the current session id.
81
+ - `subscribe(listener)`: receives normalized `AgentCoreSessionEvent` payloads, including `session_start`.
82
+ - `abort()`: aborts the active run if one is in progress.
83
+ - `dispose()`: aborts the active run, clears listeners, and drops queued follow-ups.
84
+ - `executeCommand()` / `executeBash()`: local shell helpers scoped to `options.workspace`.
85
+ - `sessionId` / `isStreaming`: getters for the active continued session id and current streaming state.
86
+
87
+ Session behavior that matters to host integrations:
88
+
89
+ - Agent-core reuses the `sessionId` learned from prior runs, so later prompts continue the same adapters session when the backend supports it.
90
+ - Agent-core also keeps successful user/assistant turns on the session handle and includes bounded prior history in later direct provider prompts. System prompts are rebuilt from options for each request and are not stored in mutable history.
91
+ - Failed prompts, timed-out requests, aborted requests, and malformed streams do not append partial assistant output to history.
92
+ - Concurrent `prompt()` calls on the same handle are rejected.
93
+ - Event payloads are normalized before subscribers see them. Non-object payloads become `{ type: "unknown", value }`.
94
+ - Approval mode is `prompt` only when `uiContext` is present; otherwise genty-core uses `yolo`.
95
+
96
+ ### Supported runtime options
97
+
98
+ | Option | Runtime effect |
99
+ | --- | --- |
100
+ | `workspace` | Forwarded to adapters as `cwd`. |
101
+ | `model` | Forwarded to adapters as `model`. |
102
+ | `timeout` | Forwarded to adapters as `timeout`. |
103
+ | `maxHistoryTurns` | Maximum persisted user/assistant history entries retained on the session handle. Defaults to 20. |
104
+ | `maxHistoryTokens` | Maximum estimated tokens from prior history sent with a prompt. Uses the package's provider/model-aware rough token estimator and drops oldest entries first. |
105
+ | `thinkingLevel` | Translated to adapters `thinkingEffort` (`minimal`/`low` -> `low`, `medium` -> `medium`, `high` -> `high`, `xhigh` -> `max`). |
106
+ | `systemPrompt` | Used as the base `systemPrompt`. |
107
+ | `appendSystemPrompt` | Appended to the final `systemPrompt` before dispatch. |
108
+ | `uiContext` | Switches run approval mode to `prompt`; when omitted, genty-core uses `yolo`. |
109
+ | `backend` | Selects the adapters adapter/backend forwarded as `agent`. |
110
+ | `outputFormat` | Optional structured-output mode: `text`, `json_object`, or `json_schema`. |
111
+ | `outputSchema` | JSON Schema used when `outputFormat` is `json_schema`. |
112
+ | `outputSchemaName` | Provider-visible schema name. Defaults to `agent_core_response`. |
113
+ | `outputSchemaStrict` | Provider strictness flag for schema-capable APIs. Defaults to `true` for `json_schema`. |
114
+
115
+ ### Structured Output
116
+
117
+ Structured output is opt-in. Plain `prompt(text, timeout?)` remains the default and returns only the text output fields used by existing callers.
118
+
119
+ ```ts
120
+ const session = createAgentCoreSession({
121
+ model: "gpt-5.5",
122
+ outputFormat: "json_schema",
123
+ outputSchemaName: "answer_payload",
124
+ outputSchema: {
125
+ type: "object",
126
+ required: ["answer"],
127
+ properties: {
128
+ answer: { type: "string" },
129
+ },
130
+ },
131
+ });
132
+
133
+ const result = await session.prompt<{ answer: string }>("Answer as JSON");
134
+ if (result.success) {
135
+ console.log(result.parsed?.answer);
136
+ } else {
137
+ console.error(result.validationError ?? result.output);
138
+ }
139
+ ```
140
+
141
+ OpenAI-compatible and Azure endpoints receive `response_format` with either `{ type: "json_object" }` or a `json_schema` payload. Anthropic does not expose the same response-format field through this direct Messages API path, so genty-core injects a system instruction that requires JSON-only output and still parses/validates the returned text locally.
142
+
143
+ `json_object` requires the model to return a JSON object. `json_schema` requires `outputSchema` and validates the parsed object for common JSON Schema constraints used by this package contract (`type`, `required`, `properties`, `items`, and `enum`). Parse or schema failures return `success: false`, `exitCode: 1`, the raw `output`, and `validationError`.
144
+
145
+ Prompt-level options can override session defaults:
146
+
147
+ ```ts
148
+ const result = await session.prompt<{ ok: boolean }>("Return status", {
149
+ outputFormat: "json_object",
150
+ });
151
+ ```
152
+
153
+ ### Multimodal Input
154
+
155
+ `prompt()` accepts an array of prompt parts for text plus image URL/base64 input:
156
+
157
+ ```ts
158
+ await session.prompt([
159
+ { type: "text", text: "Describe the relevant details in these images." },
160
+ { type: "image_url", imageUrl: "https://example.com/screenshot.png" },
161
+ { type: "image_base64", mediaType: "image/png", data: rawBase64Png },
162
+ ]);
163
+ ```
164
+
165
+ OpenAI-compatible and Azure endpoints receive Chat Completions content parts using `text` and `image_url`. Base64 images are converted to `data:<mediaType>;base64,...` URLs for those providers. Anthropic receives Messages API content blocks with `image` sources using either `url` or `base64`.
166
+
167
+ Agent-core validates image URLs before dispatch (`http`/`https` only), requires `image/*` media types for base64 images, rejects data URLs in the base64 field, and caps raw base64 image payloads at 20 MiB. Image-bearing `ToolResult` support remains owned by #588; this API only covers direct session prompt input.
168
+
169
+ ### Deprecated compatibility fields
170
+
171
+ These fields remain on `AgentCoreSessionOptions` for compatibility, but the current runtime ignores them:
172
+
173
+ | Option | Status | Migration note |
174
+ | --- | --- | --- |
175
+ | `toolsMode` | Deprecated, ignored by genty-core | Use backend-native configuration, or the PI wrapper in `@a5c-ai/genty-platform`, if you still need tool-surface control. |
176
+ | `customTools` | Deprecated, ignored by genty-core | Register host-side tools with `createAgentCoreToolDefinitions()` or use the PI wrapper for runtime custom-tool injection. |
177
+ | `isolated` | Deprecated, ignored by genty-core | Use the PI wrapper if you still need extension/skills isolation controls. |
178
+ | `ephemeral` | Deprecated, ignored by genty-core | Session persistence is determined by the selected adapters backend. |
179
+ | `bashSandbox` | Deprecated, ignored by genty-core | Sandbox behavior belongs to the selected backend. |
180
+ | `enableCompaction` | Deprecated, ignored by genty-core | Compaction behavior belongs to the selected backend/runtime. |
181
+ | `agentDir` | Deprecated, ignored by genty-core | Configure agent directories through the target backend instead. |
182
+
183
+ If you still need the PI-era controls above, use the PI wrapper exposed from `@a5c-ai/genty-platform` rather than `@a5c-ai/genty-core`.
184
+
185
+ ## Tool-definition API
186
+
187
+ `createAgentCoreToolDefinitions(options)` returns a wrapped `CustomToolDefinition[]` assembled from:
188
+
189
+ - file-system tools: `read`, `write`, `edit`, `grep`, `find`
190
+ - execution tools: `bash`, `python`, `ssh`, `fetch`
191
+ - browser/config tools: `browser`, `config`
192
+ - delegation tools: `AskUserQuestion`, `task`, `skill`
193
+ - code tools: `calc`, `ast_grep`, `ast_edit`, `render_mermaid`, `notebook`
194
+ - background/discovery/web tools: `background_status`, `background_list`, `tool_search`, `tool_fetch`, `web_search`, `fetch_process`
195
+ - optional programmatic tool calling: `code_executor` when `programmaticToolCalling` is enabled
196
+
197
+ The `calc` tool evaluates a constrained arithmetic language only: numeric literals, parentheses, unary `+`/`-`, and `+`, `-`, `*`, `/`, `%`, and `**`. It rejects identifiers, function calls, property access, assignment, malformed expressions, overlong input, and non-finite results. It does not use `eval`, `Function`, shell execution, or external processes.
198
+
199
+ `AgentCoreToolOptions` controls how those definitions are wired into a host runtime:
200
+
201
+ - `workspace`: base directory for filesystem and execution tools.
202
+ - `interactive`: gates interactive tool behavior.
203
+ - `askUserQuestionHandler`, `taskHandler`, `skillHandler`: host-owned handlers for delegated tool calls.
204
+ - `onToolUse`: observer callback fired after tool wrapping.
205
+ - `onBackgroundComplete`, `maxBackgroundProcesses`, `backgroundRegistry`: background-process lifecycle hooks and limits.
206
+ - `deferredToolRegistry`: enables `tool_search` and `tool_fetch`.
207
+ - `programmaticToolCalling`: opt-in Code Mode / Programmatic Tool Calling surface. When enabled, `code_executor` runs a bounded JavaScript async body with `tools.<name>(params)` and `callTool(name, params)` helpers for batching existing genty-core tools behind one model-level tool call.
208
+
209
+ Example:
210
+
211
+ ```ts
212
+ const tools = createAgentCoreToolDefinitions({
213
+ workspace: process.cwd(),
214
+ interactive: false,
215
+ deferredToolRegistry,
216
+ programmaticToolCalling: { maxToolCalls: 10, timeout: 60_000 },
217
+ });
218
+ ```
219
+
220
+ ### Interactive and cancellation contract
221
+
222
+ - `interactive: false` disables `AskUserQuestion` even if `askUserQuestionHandler` is supplied. Both simple and structured calls return `Error: AskUserQuestion is unavailable when interactive=false.` and the handler is never invoked.
223
+ - `CustomToolDefinition.execute()` does not receive a shared `AbortSignal`. Long-running tools must own their own timeout/cancellation behavior.
224
+ - Synchronous throws and rejected promises are normalized into `Error: ...` tool results.
225
+ - Timeout-driven aborts are normalized to `Error: Tool execution was cancelled.`
226
+
227
+ ### Background-task lifecycle caveats
228
+
229
+ Background tasks are scoped to the returned tool-definition array, not to a module-global singleton.
230
+
231
+ - `background_list` and `background_status` only expose tasks started by that same definition set.
232
+ - `maxBackgroundProcesses` is enforced per scoped registry.
233
+ - `disposeAgentCoreToolDefinitions(definitions)` kills still-running background tasks and clears retained stdout/stderr/task records for that definition set.
234
+ - If you inject a custom `backgroundRegistry`, ownership moves to the caller and you must dispose it yourself.
235
+
236
+ ### Config tool state
237
+
238
+ The `config` tool reads Babysitter defaults from `@a5c-ai/babysitter-sdk` and also supports run-scoped in-memory overrides plus selected global env-var writes.
239
+
240
+ Call `resetRunScopedConfig()` between independent runs if your host process reuses the same genty-core module instance and you do not want config overrides to leak across runs.
241
+
242
+ ## DeferredToolRegistry API
243
+
244
+ `DeferredToolRegistry` is the package's lazy schema registry for non-bundled tools.
245
+
246
+ Typical flow:
247
+
248
+ 1. Register tier-1 entries with `registerTools()`.
249
+ 2. Register per-source loaders with `registerLoader()`.
250
+ 3. Use `tool_search` or `searchTools()` for lightweight discovery by name/description.
251
+ 4. Use `tool_fetch` or `fetchSchema()` to lazily load and cache a full schema.
252
+
253
+ Useful methods:
254
+
255
+ - `registerTools(entries)`
256
+ - `registerLoader(source, loader)`
257
+ - `getAllEntries()`
258
+ - `getEntriesBySource(source, sourceQualifier?)`
259
+ - `searchTools(query, maxResults?)`
260
+ - `fetchSchema(toolName, source?, sourceQualifier?)`
261
+ - `removeToolsBySource(source, sourceQualifier?)`
262
+ - `clear()`
263
+ - `size` / `loadedSchemaCount`
264
+
265
+ Source disambiguation uses `(source, sourceQualifier, name)`, so duplicate tool names from different MCP servers or plugins can coexist safely.
266
+
267
+ ## Integration points
268
+
269
+ Current downstream integration boundaries in this repo:
270
+
271
+ - `@a5c-ai/genty-platform`
272
+ - re-exports the session/tool APIs from `src/harness/index.ts`
273
+ - uses `createAgentCoreSession()` for the direct `genty-core` harness path in `src/harness/invoker.ts`
274
+ - injects `createAgentCoreToolDefinitions()` into plan-process and delegated-task flows in `src/harness/internal/createRun/planProcess/*`
275
+ - uses both session and tool-definition APIs in `src/cli/commands/harness/resumeRun.ts` to inspect and resume existing runs
276
+ - `@a5c-ai/adapters`
277
+ - provides the actual client, built-in adapters, session continuation, approval mode, and backend selection that genty-core forwards into
278
+ - `@a5c-ai/babysitter-sdk`
279
+ - provides config defaults/env wiring used by the `config` tool and remains the owner of orchestration/run-state semantics outside this package
280
+
281
+ In practice, use `genty-core` when you need an in-process runtime wrapper or bundled tool surface. Use `agent-platform` when you need the higher-level harness CLI/runtime entrypoints.
282
+
283
+ ## Build, test, and CI
284
+
285
+ From the repo root:
286
+
287
+ ```bash
288
+ npm run build --workspace=@a5c-ai/genty-core
289
+ npm run test --workspace=@a5c-ai/genty-core
290
+ ```
291
+
292
+ The package `build` script invokes the root `build:runtime:genty-core-deps` entrypoint before `tsc --build`, so fresh-checkout builds do not depend on prebuilt upstream `dist/` output.
293
+
294
+ Package-local `test` runs `vitest` against:
295
+
296
+ - `src/session.test.ts` for session option/event/continuation behavior
297
+ - `src/tools.test.ts` for tool-surface behavior, background-task scoping, AskUserQuestion gating, and helper exports
298
+ - `src/deferredToolRegistry.test.ts` for registry search, fetch, cache, and removal behavior
299
+
300
+ For the shared runtime chain used by release-oriented workflows, run:
301
+
302
+ ```bash
303
+ npm run build:runtime
304
+ ```
305
+
306
+ Per [Workspace Validation Map](../../docs/workspace-validation.md), `packages/genty/core` is a public advanced/runtime package validated by `.github/workflows/ci.yml` job `test` and by the release/staging workflows. Keep README claims aligned with those validation paths rather than inventing package-specific CI jobs that do not exist.
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Backwards-compatibility shim -- the canonical implementation now lives in
3
+ * `@a5c-ai/genty-runtime`. This re-export keeps internal agent-core consumers
4
+ * working without changes.
5
+ */
6
+ export { getBackgroundRegistry, disposeBackgroundRegistry, } from "@a5c-ai/genty-runtime";
7
+ //# sourceMappingURL=state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../src/agenticTools/background/state.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EACL,qBAAqB,EACrB,yBAAyB,GAC1B,MAAM,uBAAuB,CAAC"}
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.disposeBackgroundRegistry = exports.getBackgroundRegistry = void 0;
4
+ /**
5
+ * Backwards-compatibility shim -- the canonical implementation now lives in
6
+ * `@a5c-ai/genty-runtime`. This re-export keeps internal agent-core consumers
7
+ * working without changes.
8
+ */
9
+ var genty_runtime_1 = require("@a5c-ai/genty-runtime");
10
+ Object.defineProperty(exports, "getBackgroundRegistry", { enumerable: true, get: function () { return genty_runtime_1.getBackgroundRegistry; } });
11
+ Object.defineProperty(exports, "disposeBackgroundRegistry", { enumerable: true, get: function () { return genty_runtime_1.disposeBackgroundRegistry; } });
@@ -0,0 +1,3 @@
1
+ import type { AgenticToolOptions, CustomToolDefinition } from "../types";
2
+ export declare function createBackgroundTools(options: AgenticToolOptions): CustomToolDefinition[];
3
+ //# sourceMappingURL=tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../../src/agenticTools/background/tools.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAIzE,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,kBAAkB,GAAG,oBAAoB,EAAE,CA+BzF"}
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createBackgroundTools = createBackgroundTools;
4
+ const typebox_1 = require("@sinclair/typebox");
5
+ const results_1 = require("../shared/results");
6
+ const state_1 = require("./state");
7
+ function createBackgroundTools(options) {
8
+ return [
9
+ {
10
+ name: "background_status",
11
+ label: "Background Task Status",
12
+ description: "Query the status of a background task by its backgroundTaskId. Returns the task record including status, stdout, stderr, and exit code.",
13
+ parameters: typebox_1.Type.Object({
14
+ backgroundTaskId: typebox_1.Type.String({
15
+ description: "The backgroundTaskId returned when launching a background task",
16
+ }),
17
+ }),
18
+ execute: (_toolCallId, params) => {
19
+ const backgroundTaskId = String(params.backgroundTaskId);
20
+ const record = (0, state_1.getBackgroundRegistry)(options).get(backgroundTaskId);
21
+ if (!record) {
22
+ return (0, results_1.errorResult)(`Background task not found: ${backgroundTaskId}`);
23
+ }
24
+ return (0, results_1.jsonResult)(record);
25
+ },
26
+ },
27
+ {
28
+ name: "background_list",
29
+ label: "List Background Tasks",
30
+ description: "List all tracked background tasks with their current status.",
31
+ parameters: typebox_1.Type.Object({}),
32
+ execute: () => (0, results_1.jsonResult)({
33
+ tasks: (0, state_1.getBackgroundRegistry)(options).list(),
34
+ }),
35
+ },
36
+ ];
37
+ }
@@ -0,0 +1,3 @@
1
+ import type { CustomToolDefinition } from "../types";
2
+ export declare function createBrowserTool(): CustomToolDefinition;
3
+ //# sourceMappingURL=tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../../../src/agenticTools/browser/tool.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAoBrD,wBAAgB,iBAAiB,IAAI,oBAAoB,CA+DxD"}
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createBrowserTool = createBrowserTool;
4
+ const typebox_1 = require("@sinclair/typebox");
5
+ const results_1 = require("../shared/results");
6
+ let browserInstance = null;
7
+ function createBrowserTool() {
8
+ return {
9
+ name: "browser",
10
+ label: "Headless Browser",
11
+ description: "Interact with a headless browser. Actions: navigate, click, type, evaluate, screenshot, close.",
12
+ parameters: typebox_1.Type.Object({
13
+ action: typebox_1.Type.String({
14
+ description: "Action: navigate | click | type | evaluate | screenshot | close",
15
+ }),
16
+ url: typebox_1.Type.Optional(typebox_1.Type.String({ description: "URL to navigate to" })),
17
+ selector: typebox_1.Type.Optional(typebox_1.Type.String({ description: "CSS selector for click/type" })),
18
+ text: typebox_1.Type.Optional(typebox_1.Type.String({ description: "Text to type" })),
19
+ script: typebox_1.Type.Optional(typebox_1.Type.String({ description: "JavaScript to evaluate in page" })),
20
+ options: typebox_1.Type.Optional(typebox_1.Type.Object({}, { additionalProperties: true })),
21
+ }),
22
+ execute: async (_toolCallId, params) => {
23
+ let puppeteer;
24
+ try {
25
+ // eslint-disable-next-line @typescript-eslint/no-implied-eval, @typescript-eslint/no-unsafe-assignment
26
+ puppeteer = await new Function("id", "return import(id)")("puppeteer");
27
+ }
28
+ catch (error) {
29
+ return (0, results_1.errorResult)(`puppeteer import failed: ${error instanceof Error ? error.message : String(error)}. Install with: npm install puppeteer`);
30
+ }
31
+ if (!browserInstance) {
32
+ browserInstance = await puppeteer.launch({
33
+ headless: true,
34
+ args: ["--no-sandbox", "--disable-setuid-sandbox"],
35
+ });
36
+ }
37
+ const browser = browserInstance;
38
+ const page = (await browser.pages())[0] ?? await browser.newPage();
39
+ switch (String(params.action)) {
40
+ case "navigate":
41
+ await page.goto(String(params.url), { waitUntil: "domcontentloaded" });
42
+ return (0, results_1.ok)(`Navigated to ${String(params.url)} — title: ${await page.title()}`);
43
+ case "click":
44
+ await page.click(String(params.selector));
45
+ return (0, results_1.ok)(`Clicked ${String(params.selector)}`);
46
+ case "type":
47
+ await page.type(String(params.selector), String(params.text));
48
+ return (0, results_1.ok)(`Typed into ${String(params.selector)}`);
49
+ case "evaluate":
50
+ return (0, results_1.jsonResult)(await page.evaluate(String(params.script)));
51
+ case "screenshot": {
52
+ const buffer = await page.screenshot({ encoding: "base64" });
53
+ return (0, results_1.ok)(`Screenshot captured (${buffer.length} base64 chars).`);
54
+ }
55
+ case "close":
56
+ await browser.close();
57
+ browserInstance = null;
58
+ return (0, results_1.ok)("Browser closed.");
59
+ default:
60
+ return (0, results_1.errorResult)(`Unknown browser action: ${String(params.action)}`);
61
+ }
62
+ },
63
+ };
64
+ }
@@ -0,0 +1,10 @@
1
+ export declare const resetRunScopedConfig: () => void;
2
+ export declare const isValidConfigKey: (key: string) => boolean;
3
+ export declare const validateConfigValue: (key: string, value: unknown) => string | null;
4
+ export declare const getConfigValue: (key: string) => unknown;
5
+ export declare const getConfigDefault: (key: string) => unknown;
6
+ export declare const listConfigKeys: () => string[];
7
+ export declare const getRunScopedConfigEntries: () => IterableIterator<[string, unknown]>;
8
+ export declare const setConfigValue: (key: string, value: unknown, scope: string) => void;
9
+ export declare const resetConfigValue: (key?: string) => void;
10
+ //# sourceMappingURL=state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../src/agenticTools/config/state.ts"],"names":[],"mappings":"AA+BA,eAAO,MAAM,oBAAoB,YAA6B,CAAC;AAC/D,eAAO,MAAM,gBAAgB,0BAAyB,CAAC;AACvD,eAAO,MAAM,mBAAmB,gDAA4B,CAAC;AAC7D,eAAO,MAAM,cAAc,0BAAuB,CAAC;AACnD,eAAO,MAAM,gBAAgB,0BAAyB,CAAC;AACvD,eAAO,MAAM,cAAc,gBAAuB,CAAC;AACnD,eAAO,MAAM,yBAAyB,2CAAkC,CAAC;AACzE,eAAO,MAAM,cAAc,sDAAuB,CAAC;AACnD,eAAO,MAAM,gBAAgB,wBAAyB,CAAC"}
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resetConfigValue = exports.setConfigValue = exports.getRunScopedConfigEntries = exports.listConfigKeys = exports.getConfigDefault = exports.getConfigValue = exports.validateConfigValue = exports.isValidConfigKey = exports.resetRunScopedConfig = void 0;
4
+ const babysitter_sdk_1 = require("@a5c-ai/babysitter-sdk");
5
+ const EXTENDED_CONFIG_KEYS = new Set([
6
+ "model",
7
+ "provider",
8
+ "breakpoint.autoApproveAfterN",
9
+ "breakpoint.presentAlwaysApprove",
10
+ ]);
11
+ const CONFIG_KEY_TYPES = {
12
+ runsDir: "string",
13
+ maxIterations: "number",
14
+ qualityThreshold: "number",
15
+ timeout: "number",
16
+ logLevel: "string",
17
+ allowSecretLogs: "boolean",
18
+ hookTimeout: "number",
19
+ nodeTaskTimeout: "number",
20
+ clockStepMs: "number",
21
+ clockStartMs: "number",
22
+ layoutVersion: "string",
23
+ largeResultPreviewLimit: "number",
24
+ model: "string",
25
+ provider: "string",
26
+ };
27
+ const state = (0, babysitter_sdk_1.createScopedRuntimeConfigState)({
28
+ configKeyTypes: CONFIG_KEY_TYPES,
29
+ extendedConfigKeys: EXTENDED_CONFIG_KEYS,
30
+ });
31
+ exports.resetRunScopedConfig = state.resetRunScopedConfig;
32
+ exports.isValidConfigKey = state.isValidConfigKey;
33
+ exports.validateConfigValue = state.validateConfigValue;
34
+ exports.getConfigValue = state.getConfigValue;
35
+ exports.getConfigDefault = state.getConfigDefault;
36
+ exports.listConfigKeys = state.listConfigKeys;
37
+ exports.getRunScopedConfigEntries = state.getRunScopedConfigEntries;
38
+ exports.setConfigValue = state.setConfigValue;
39
+ exports.resetConfigValue = state.resetConfigValue;
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=state.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.test.d.ts","sourceRoot":"","sources":["../../../src/agenticTools/config/state.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vitest_1 = require("vitest");
4
+ const state_1 = require("./state");
5
+ (0, vitest_1.describe)("agent-core config state", () => {
6
+ (0, vitest_1.it)("does not write global config scope into process.env", () => {
7
+ const previous = process.env.BABYSITTER_LOG_LEVEL;
8
+ delete process.env.BABYSITTER_LOG_LEVEL;
9
+ try {
10
+ (0, state_1.resetConfigValue)();
11
+ (0, state_1.setConfigValue)("logLevel", "debug", "global");
12
+ (0, vitest_1.expect)(process.env.BABYSITTER_LOG_LEVEL).toBeUndefined();
13
+ (0, vitest_1.expect)((0, state_1.getConfigValue)("logLevel")).toBe("debug");
14
+ }
15
+ finally {
16
+ (0, state_1.resetConfigValue)();
17
+ if (previous === undefined)
18
+ delete process.env.BABYSITTER_LOG_LEVEL;
19
+ else
20
+ process.env.BABYSITTER_LOG_LEVEL = previous;
21
+ }
22
+ });
23
+ });
@@ -0,0 +1,3 @@
1
+ import type { CustomToolDefinition } from "../types";
2
+ export declare function createConfigTool(): CustomToolDefinition;
3
+ //# sourceMappingURL=tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../../../src/agenticTools/config/tool.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAarD,wBAAgB,gBAAgB,IAAI,oBAAoB,CAuFvD"}
@@ -0,0 +1,87 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createConfigTool = createConfigTool;
4
+ const typebox_1 = require("@sinclair/typebox");
5
+ const results_1 = require("../shared/results");
6
+ const state_1 = require("./state");
7
+ function createConfigTool() {
8
+ return {
9
+ name: "config",
10
+ label: "Runtime Config",
11
+ description: "Read and modify babysitter configuration at runtime. Supports get/set/list/reset actions for standard config keys, model/provider selection, and compression settings.",
12
+ parameters: typebox_1.Type.Object({
13
+ action: typebox_1.Type.Union([
14
+ typebox_1.Type.Literal("get"),
15
+ typebox_1.Type.Literal("set"),
16
+ typebox_1.Type.Literal("list"),
17
+ typebox_1.Type.Literal("reset"),
18
+ ], { description: "Action to perform: get, set, list, or reset" }),
19
+ key: typebox_1.Type.Optional(typebox_1.Type.String({ description: "Config key path (dot notation for nested, e.g. 'compression.enabled')" })),
20
+ value: typebox_1.Type.Optional(typebox_1.Type.Unknown({ description: "New value for set action" })),
21
+ scope: typebox_1.Type.Optional(typebox_1.Type.Union([typebox_1.Type.Literal("run"), typebox_1.Type.Literal("global")], {
22
+ description: "Scope: 'run' (default) or 'global' process-scoped config",
23
+ })),
24
+ }),
25
+ execute: (_toolCallId, params) => {
26
+ const action = params.action;
27
+ if (!action) {
28
+ return (0, results_1.errorResult)("'action' parameter is required (get, set, list, reset).");
29
+ }
30
+ const key = params.key;
31
+ const value = params.value;
32
+ const scope = params.scope ?? "run";
33
+ switch (action) {
34
+ case "get":
35
+ if (!key) {
36
+ const merged = {};
37
+ for (const configKey of (0, state_1.listConfigKeys)()) {
38
+ merged[configKey] = (0, state_1.getConfigValue)(configKey);
39
+ }
40
+ return (0, results_1.jsonResult)(merged);
41
+ }
42
+ if (!(0, state_1.isValidConfigKey)(key)) {
43
+ return (0, results_1.errorResult)(`Error: Unknown config key '${key}'.`);
44
+ }
45
+ return (0, results_1.jsonResult)({ key, value: (0, state_1.getConfigValue)(key) });
46
+ case "set":
47
+ if (!key) {
48
+ return (0, results_1.errorResult)("Error: 'key' parameter is required for set action.");
49
+ }
50
+ if (value === undefined) {
51
+ return (0, results_1.errorResult)("Error: 'value' parameter is required for set action.");
52
+ }
53
+ if (!(0, state_1.isValidConfigKey)(key)) {
54
+ return (0, results_1.errorResult)(`Error: Unknown config key '${key}'.`);
55
+ }
56
+ {
57
+ const validationError = (0, state_1.validateConfigValue)(key, value);
58
+ if (validationError) {
59
+ return (0, results_1.errorResult)(`Error: ${validationError}`);
60
+ }
61
+ }
62
+ (0, state_1.setConfigValue)(key, value, scope);
63
+ return (0, results_1.ok)(`Set '${key}' to ${JSON.stringify(value)} (scope: ${scope}).`);
64
+ case "list": {
65
+ const entries = {};
66
+ for (const configKey of (0, state_1.listConfigKeys)()) {
67
+ entries[configKey] = {
68
+ current: (0, state_1.getConfigValue)(configKey),
69
+ default: (0, state_1.getConfigDefault)(configKey),
70
+ };
71
+ }
72
+ for (const [configKey, configValue] of (0, state_1.getRunScopedConfigEntries)()) {
73
+ if (!entries[configKey]) {
74
+ entries[configKey] = { current: configValue, default: undefined };
75
+ }
76
+ }
77
+ return (0, results_1.jsonResult)(entries);
78
+ }
79
+ case "reset":
80
+ (0, state_1.resetConfigValue)(key);
81
+ return (0, results_1.ok)(key ? `Reset '${key}' to default.` : "Reset all config to defaults.");
82
+ default:
83
+ return (0, results_1.errorResult)(`Error: Unknown action '${action}'. Use get, set, list, or reset.`);
84
+ }
85
+ },
86
+ };
87
+ }
@@ -0,0 +1,3 @@
1
+ import type { AgenticToolOptions, CustomToolDefinition } from "../types";
2
+ export declare function createDiscoveryTools(options: AgenticToolOptions): CustomToolDefinition[];
3
+ //# sourceMappingURL=tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../../src/agenticTools/discovery/tools.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAGzE,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,kBAAkB,GAAG,oBAAoB,EAAE,CA4ExF"}