@prismshadow/penguin-core 0.0.1
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/LICENSE +201 -0
- package/README.md +41 -0
- package/dist/chunk-FX4CCIN7.js +379 -0
- package/dist/chunk-FX4CCIN7.js.map +1 -0
- package/dist/chunk-HRIXWKKE.js +1 -0
- package/dist/chunk-HRIXWKKE.js.map +1 -0
- package/dist/chunk-JC6SC6KF.js +336 -0
- package/dist/chunk-JC6SC6KF.js.map +1 -0
- package/dist/index.d.ts +1462 -0
- package/dist/index.js +5187 -0
- package/dist/index.js.map +1 -0
- package/dist/interfaces-CMSN7-pO.d.ts +487 -0
- package/dist/interfaces.d.ts +2 -0
- package/dist/interfaces.js +2 -0
- package/dist/interfaces.js.map +1 -0
- package/dist/model-catalog-DTu0IPjs.d.ts +266 -0
- package/dist/omnimessage/index.d.ts +110 -0
- package/dist/omnimessage/index.js +69 -0
- package/dist/omnimessage/index.js.map +1 -0
- package/dist/state/model-catalog.d.ts +1 -0
- package/dist/state/model-catalog.js +19 -0
- package/dist/state/model-catalog.js.map +1 -0
- package/dist/types-D6FERSdT.d.ts +293 -0
- package/package.json +58 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,1462 @@
|
|
|
1
|
+
import { O as OmniMessage, S as StopReason, C as CompactionMode, b as TokenCounts, T as ToolDefinition, c as CompleteModelMessage, d as SessionMetaMessage, e as SessionMetaPayload } from './types-D6FERSdT.js';
|
|
2
|
+
export { f as AbortPayload, A as ApprovalDecision, g as ApprovalDecisionPayload, h as CompactionBeginPayload, i as CompactionEndPayload, j as CompactionReason, k as CompleteModelPayload, E as EventMessage, l as EventPayload, I as ImageUrlPayload, m as InlineDataPayload, n as InlineThinkingPayload, M as MessageOrigin, o as ModelMessage, p as ModelPayload, q as OmniMessageType, r as OmniPayload, P as PartialModelMessage, s as PartialModelPayload, t as PartialTextPayload, u as PartialThinkingPayload, v as PartialToolCallOutputPayload, w as PartialToolCallPayload, R as RequestBeginPayload, x as RequestEndPayload, y as Role, z as StreamEventType, B as SubagentPayload, D as TextPayload, F as ThinkingPayload, G as TokenUsagePayload, H as ToolCallOutputPayload, a as ToolCallPayload, J as isCompleteModelMessage, K as isEventMessage, L as isModelMessage, N as isPartialPayload, Q as isSessionMeta } from './types-D6FERSdT.js';
|
|
3
|
+
export { FidelityFields, PartialAggregator, abortEvent, addTokenCounts, aggregateAll, approvalDecision, assistantText, compactionBegin, compactionEnd, emptyTokenCounts, imageUrlMessage, inlineData, inlineThinking, partialText, partialThinking, partialToolCall, partialToolCallOutput, requestBegin, requestEnd, sessionMeta, subagentEvent, textMessage, thinkingMessage, tokenUsage, toolCall, toolCallOutput, userText, withOrigin } from './omnimessage/index.js';
|
|
4
|
+
import { T as ToolDefinitionConfig, A as ApproveFn, a as ThinkingLevelName, M as MCPServerConfig, b as ToolConfig, c as ToolCallIdAllocator, L as LLMInterface, G as GenerativeModelConfig, d as GenerativeModelParameters, e as LLMOutcome, E as EnvironmentInterface, f as EnvironmentConfig, g as ToolPermission, h as ToolExecutionRequest, i as EnvironmentServices } from './interfaces-CMSN7-pO.js';
|
|
5
|
+
export { C as CommandSessionManager, j as ManagedSession, k as ManagedSubagentSession, P as ProcessExit, S as SpawnOptions, l as SubagentHandle, m as SubagentRunner, n as SubagentSessionManager, V as VisionDescriberService, s as stripToolCallIdSuffix } from './interfaces-CMSN7-pO.js';
|
|
6
|
+
import { LibrarySkill, SkillMetadata } from '@prismshadow/penguin-skills';
|
|
7
|
+
export { SkillMetadata, parseSkillFrontmatter } from '@prismshadow/penguin-skills';
|
|
8
|
+
import { P as ProjectConfig } from './model-catalog-DTu0IPjs.js';
|
|
9
|
+
export { M as MODEL_CATALOG, a as MODEL_PROVIDERS, b as ModelCatalogEntry, c as ModelEntry, d as ModelEnvInfo, e as ModelPricing, f as ModelProviderInfo, g as ModelRef, h as addModel, i as catalogEntryFor, j as defaultProjectConfig, k as formatModelRef, l as getModel, m as inferProviderForUpstream, n as loadProjectConfig, p as presetModelEntries, o as providerInfo, r as renderProjectConfigToml, q as resolveModelEnv, s as resolveModelRef, t as saveProjectConfig, u as setDefaultModel, v as setVisionModel } from './model-catalog-DTu0IPjs.js';
|
|
10
|
+
import { UniEvent, UniMessage, UniConfig, ThinkingLevel, ToolSchema, UsageMetadata } from '@prismshadow/agenthub';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* BuiltinTool abstraction — lets Environment avoid special-casing any specific tool name.
|
|
14
|
+
*
|
|
15
|
+
* Each builtin tool carries its own: `name`, the `definition` handed to the LLM, and a streaming
|
|
16
|
+
* `execute`. Environment dispatches purely by looking up `name`; an unknown tool collapses to an
|
|
17
|
+
* explanatory `tool_call_output`, never throwing. Adding a new tool later (e.g. file read/write,
|
|
18
|
+
* retrieval) only requires implementing this interface and registering it with the registry, with
|
|
19
|
+
* no changes needed to Environment.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Tool execution context: runtime information needed to execute one tool call.
|
|
24
|
+
* Docs: /docs/tools § "Execution contract".
|
|
25
|
+
*/
|
|
26
|
+
interface ToolExecutionContext {
|
|
27
|
+
/** Workspace absolute path; relative-path arguments should be resolved against it. */
|
|
28
|
+
workspaceDir: string;
|
|
29
|
+
/** The tool_call_id passed through unchanged, used to build streaming deltas and nested origin tags. */
|
|
30
|
+
toolCallId: string;
|
|
31
|
+
/** Abort signal; the tool should close out and return as soon as possible once it fires. */
|
|
32
|
+
signal?: AbortSignal;
|
|
33
|
+
/** The parent Agent's approval callback; run_subagent passes it through to the child Session so it inherits the parent's approval mode (unused by most tools). */
|
|
34
|
+
approve?: ApproveFn;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Tool execution result (the generator's return value); treated as `completed` if omitted.
|
|
38
|
+
* Docs: /docs/tools § "Execution contract".
|
|
39
|
+
*/
|
|
40
|
+
interface ToolResult {
|
|
41
|
+
stopReason?: StopReason;
|
|
42
|
+
/**
|
|
43
|
+
* Terminal marker (e.g. `[exit code: 1]`): appended by Environment during its unified
|
|
44
|
+
* close-out, **outside** the maxOutputLength truncation, and streamed to the frontend as an
|
|
45
|
+
* extra chunk — so the failure marker isn't lost when long output gets truncated (it would be
|
|
46
|
+
* cut off if produced as a content delta instead).
|
|
47
|
+
*/
|
|
48
|
+
note?: string;
|
|
49
|
+
/**
|
|
50
|
+
* Images carried by the tool output (e.g. an image read by read_image): each entry is a
|
|
51
|
+
* `data:<mime>;base64,...` data URL. Attached by Environment during close-out: a single
|
|
52
|
+
* streaming delta carries it all at once before stop, plus the final complete
|
|
53
|
+
* `tool_call_output` (only carried on normal completion; images are not chunked and don't
|
|
54
|
+
* count toward text truncation).
|
|
55
|
+
*/
|
|
56
|
+
images?: string[];
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Builtin tool interface. `execute` receives the already-parsed tool argument object and the
|
|
60
|
+
* execution context, streaming out OmniMessage as an async generator. Contract (a relaxed
|
|
61
|
+
* version — framing and close-out are handled uniformly by Environment):
|
|
62
|
+
*
|
|
63
|
+
* - **Own output**: yielding the **delta** of `partial_tool_call_output` is enough; `start`/`stop`
|
|
64
|
+
* are optional (Environment ignores the tool's start/stop and frames it itself), and there's
|
|
65
|
+
* **no need** to produce a complete `tool_call_output` either (the complete message,
|
|
66
|
+
* maxOutputLength forward truncation, and close-out are all derived by Environment from the
|
|
67
|
+
* deltas). If a tool does produce a complete `tool_call_output` anyway, Environment uses it as
|
|
68
|
+
* the basis for content and stop reason (tolerated for compatibility, not recommended).
|
|
69
|
+
* - **Nested forwarding**: yielding any message **tagged with origin** is passed through by
|
|
70
|
+
* Environment unchanged (e.g. run_subagent forwarding all of a child session's messages).
|
|
71
|
+
* - **Stop reason**: reported via the generator's return value (defaults to completed); a throw
|
|
72
|
+
* is collapsed by Environment into aborted/failed based on interruption/error, never
|
|
73
|
+
* propagating up as an exception.
|
|
74
|
+
* Docs: /docs/interfaces § "The inner tool contract: BuiltinTool"; /docs/tools § "Execution contract".
|
|
75
|
+
*/
|
|
76
|
+
interface BuiltinTool {
|
|
77
|
+
/** Tool name (corresponds to the tool_call.name returned by the LLM). */
|
|
78
|
+
name: string;
|
|
79
|
+
/** Tool definition handed to the LLM (including description / parameters / permission / maxOutputLength). */
|
|
80
|
+
definition: ToolDefinitionConfig;
|
|
81
|
+
/** Executes one tool call: args is the already-parsed argument object, ctx is the runtime context. */
|
|
82
|
+
execute(args: Record<string, unknown>, ctx: ToolExecutionContext): AsyncGenerator<OmniMessage, ToolResult | void>;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** Default Project id used when none is specified. */
|
|
86
|
+
declare const DEFAULT_PROJECT_ID = "default_project";
|
|
87
|
+
/** Default Agent id used when none is specified. */
|
|
88
|
+
declare const DEFAULT_AGENT_ID = "default_agent";
|
|
89
|
+
/**
|
|
90
|
+
* Resolves the local data root directory.
|
|
91
|
+
* Prefers the `PENGUIN_HOME` environment variable, otherwise falls back to `~/.penguin/data`
|
|
92
|
+
* (under the hidden `~/.penguin` home so it never collides with unrelated folders, and in a
|
|
93
|
+
* `data/` subdir kept separate from the installer's binaries under `~/.penguin`).
|
|
94
|
+
*/
|
|
95
|
+
declare function resolveRoot(): string;
|
|
96
|
+
/** `<root>/<projectId>`. */
|
|
97
|
+
declare function projectDir(root: string, projectId: string): string;
|
|
98
|
+
/** `<projectDir>/agents`, the container directory holding every Agent in the Project. */
|
|
99
|
+
declare function agentsDir(root: string, projectId: string): string;
|
|
100
|
+
/** `<projectDir>/agents/<agentId>`. */
|
|
101
|
+
declare function agentDir(root: string, projectId: string, agentId: string): string;
|
|
102
|
+
/** `<agentDir>/agent_state`. */
|
|
103
|
+
declare function agentStateDir(root: string, projectId: string, agentId: string): string;
|
|
104
|
+
/** `<agentDir>/traces`. */
|
|
105
|
+
declare function tracesDir(root: string, projectId: string, agentId: string): string;
|
|
106
|
+
/** `<agentDir>/scratchpad`, the Agent's temporary/draft file directory (the model creates a subdirectory per Session id). */
|
|
107
|
+
declare function scratchpadDir(root: string, projectId: string, agentId: string): string;
|
|
108
|
+
/** `<agentDir>/workspaces`. */
|
|
109
|
+
declare function workspacesDir(root: string, projectId: string, agentId: string): string;
|
|
110
|
+
/**
|
|
111
|
+
* `<projectDir>/.project_config.toml`, the Project's single config file (a hidden file, not
|
|
112
|
+
* shown by default `ls`, written with mode 0600; model entries are inlined with their credential,
|
|
113
|
+
* see state/project-config.ts).
|
|
114
|
+
*/
|
|
115
|
+
declare function projectConfigPath(root: string, projectId: string): string;
|
|
116
|
+
/** `<agentStateDir>/system_config.yaml`. */
|
|
117
|
+
declare function systemConfigPath(root: string, projectId: string, agentId: string): string;
|
|
118
|
+
/** `<agentStateDir>/AGENTS.md`. */
|
|
119
|
+
declare function agentsMdPath(root: string, projectId: string, agentId: string): string;
|
|
120
|
+
/** `<agentStateDir>/.vault.toml`, the Agent-level environment-variable vault (see state/agent-vault.ts). */
|
|
121
|
+
declare function agentVaultPath(root: string, projectId: string, agentId: string): string;
|
|
122
|
+
/** `<agentStateDir>/tools`, reserved for user-defined Tool config. */
|
|
123
|
+
declare function toolsDir(root: string, projectId: string, agentId: string): string;
|
|
124
|
+
/** `<agentStateDir>/memory`. */
|
|
125
|
+
declare function memoryDir(root: string, projectId: string, agentId: string): string;
|
|
126
|
+
/** `<agentStateDir>/skills`. */
|
|
127
|
+
declare function skillsDir(root: string, projectId: string, agentId: string): string;
|
|
128
|
+
/** `<agentStateDir>/schedule`, the scheduled-task directory (doesn't exist when unconfigured). */
|
|
129
|
+
declare function scheduleDir(root: string, projectId: string, agentId: string): string;
|
|
130
|
+
/** `<agentDir>/benchmarks`, the capability-evaluation question bank and scores (doesn't exist when unconfigured). */
|
|
131
|
+
declare function benchmarksDir(root: string, projectId: string, agentId: string): string;
|
|
132
|
+
/** `<agentDir>/snapshots`, Agent State version snapshots (doesn't exist when unconfigured). */
|
|
133
|
+
declare function snapshotsDir(root: string, projectId: string, agentId: string): string;
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Default system configuration for Agent State (written to `system_config.yaml`) and the
|
|
137
|
+
* default `AGENTS.md` (empty).
|
|
138
|
+
*
|
|
139
|
+
* Runtime Prompt and tool configuration should come from editable files;
|
|
140
|
+
* code only supplies the initial defaults. `system_config.yaml` holds the relatively stable
|
|
141
|
+
* system-level Prompt, built-in tools, and MCP Server configuration; `AGENTS.md` is injected
|
|
142
|
+
* via a system Prompt placeholder.
|
|
143
|
+
*
|
|
144
|
+
* The system Prompt is sectioned and trimmed as needed (Role/Personality/Success
|
|
145
|
+
* criteria/Constraints/Stop rules/File system/Suggested workflows); it does not describe
|
|
146
|
+
* specific tools (that comes from the tool schema). AGENTS.md, Vault/Skills, and Environment
|
|
147
|
+
* injection go at the end.
|
|
148
|
+
*
|
|
149
|
+
* Placeholders (`{{...}}`) appear only in the trailing injection zones (AGENTS.md / Vault /
|
|
150
|
+
* Skills / Environment); elsewhere the body uses angle-bracket notation such as
|
|
151
|
+
* \`<project_dir>\`, \`<agent_id>\`, \`<session_id>\` — these are **not substituted**; the model
|
|
152
|
+
* fills in the actual values from the Environment section itself.
|
|
153
|
+
*/
|
|
154
|
+
|
|
155
|
+
/** Docs: /docs/configuration § "System prompt placeholders". */
|
|
156
|
+
declare const AGENTS_MD_PLACEHOLDER = "{{AGENTS_MD}}";
|
|
157
|
+
declare const VAULT_KEYS_PLACEHOLDER = "{{VAULT_KEYS}}";
|
|
158
|
+
declare const SKILL_METADATA_PLACEHOLDER = "{{SKILL_METADATA}}";
|
|
159
|
+
declare const SESSION_ID_PLACEHOLDER = "{{SESSION_ID}}";
|
|
160
|
+
declare const CWD_PLACEHOLDER = "{{CWD}}";
|
|
161
|
+
declare const AGENT_ID_PLACEHOLDER = "{{AGENT_ID}}";
|
|
162
|
+
declare const PROJECT_DIR_PLACEHOLDER = "{{PROJECT_DIR}}";
|
|
163
|
+
declare const PLATFORM_PLACEHOLDER = "{{PLATFORM}}";
|
|
164
|
+
declare const OS_VERSION_PLACEHOLDER = "{{OS_VERSION}}";
|
|
165
|
+
declare const DATE_PLACEHOLDER = "{{DATE}}";
|
|
166
|
+
/**
|
|
167
|
+
* Context compaction config (the `compaction` section of `system_config.yaml`).
|
|
168
|
+
* Docs: /docs/configuration § "Agent config".
|
|
169
|
+
*/
|
|
170
|
+
interface CompactionConfig {
|
|
171
|
+
/** Context Token threshold (taken from the most recent token_usage's request.total); defaults to 128000, <=0 disables. */
|
|
172
|
+
max_context_length?: number;
|
|
173
|
+
/** Session cumulative turn threshold (counted in LLM Requests, across Tasks); defaults to -1, <=0 means no limit. */
|
|
174
|
+
max_session_turns?: number;
|
|
175
|
+
/** Compaction mode; defaults to summarize. */
|
|
176
|
+
mode?: CompactionMode;
|
|
177
|
+
/** Prompt template for summarize compaction; defaults to the built-in value (editable config, not hardcoded). */
|
|
178
|
+
prompt?: string;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* System-level config for Agent State, serialized as `system_config.yaml`.
|
|
182
|
+
* Docs: /docs/configuration § "Agent config".
|
|
183
|
+
*/
|
|
184
|
+
interface SystemConfig {
|
|
185
|
+
/** Agent display name (display name is separate from id; falls back to id when unset). */
|
|
186
|
+
name?: string;
|
|
187
|
+
/** Agent description. */
|
|
188
|
+
description?: string;
|
|
189
|
+
/** Agent State version number: a natural number, 1 on creation, incremented on successful optimization; a missing field is treated as 1. */
|
|
190
|
+
version?: number;
|
|
191
|
+
/** System-level Prompt (relatively stable; should not be modified frequently). */
|
|
192
|
+
system_prompt: string;
|
|
193
|
+
/** Max LLM turns per Task (a runtime parameter that belongs to Agent config, not specified when creating a Session). */
|
|
194
|
+
max_turns?: number;
|
|
195
|
+
model?: {
|
|
196
|
+
max_tokens?: number;
|
|
197
|
+
thinking_level?: ThinkingLevelName;
|
|
198
|
+
timeoutMs?: number;
|
|
199
|
+
};
|
|
200
|
+
/** Context compaction (enabled by default, max_context_length 128k, mode summarize). */
|
|
201
|
+
compaction?: CompactionConfig;
|
|
202
|
+
tools?: {
|
|
203
|
+
/** Built-in system tool configuration. */
|
|
204
|
+
builtin?: ToolDefinitionConfig[];
|
|
205
|
+
/** MCP Server configuration. */
|
|
206
|
+
mcpServers?: MCPServerConfig[];
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Built-in default compaction Prompt (summarize mode): tells the model that after
|
|
211
|
+
* compaction the raw transcript is no longer visible and the
|
|
212
|
+
* summary is the only record, so it must include everything needed to continue the task,
|
|
213
|
+
* and no tools may be called while writing the summary.
|
|
214
|
+
*/
|
|
215
|
+
declare const DEFAULT_COMPACTION_PROMPT: string;
|
|
216
|
+
/** Agent State version number: an invalid or missing field is always treated as 1. */
|
|
217
|
+
declare function agentStateVersion(config: Pick<SystemConfig, "version">): number;
|
|
218
|
+
/** Returns the default system configuration for Agent State. */
|
|
219
|
+
declare function defaultSystemConfig(): SystemConfig;
|
|
220
|
+
/**
|
|
221
|
+
* Returns the default editable `AGENTS.md` content: an empty string — no guidance is
|
|
222
|
+
* preprovisioned by default; Subagent delegation conventions and general task practices
|
|
223
|
+
* live in the default template's Suggested workflows section as a soft convention.
|
|
224
|
+
* Kept so initialization can still write an empty AGENTS.md file.
|
|
225
|
+
*/
|
|
226
|
+
declare function defaultAgentsMd(): string;
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Preset content for builtin Agents; Skill documentation lives in @prismshadow/penguin-skills
|
|
230
|
+
* (the library files are read live when building the preset).
|
|
231
|
+
*
|
|
232
|
+
* - Every Project comes with a single builtin Agent: `default_agent` (the General Agent, the
|
|
233
|
+
* default conversational Agent), which has every Skill in the library installed at
|
|
234
|
+
* initialization. Dedicated capabilities (creating an Agent, optimizing an Agent, etc.)
|
|
235
|
+
* are carried by Skills rather than dedicated builtin Agents.
|
|
236
|
+
* - The preset carries no AGENTS.md: the default AGENTS.md is empty, with delegation and task
|
|
237
|
+
* conventions living in the default template's Suggested Workflows section.
|
|
238
|
+
* - Skill metadata is auto-injected into the system Prompt via the `{{SKILL_METADATA}}`
|
|
239
|
+
* placeholder; it's not registered in AGENTS.md.
|
|
240
|
+
*/
|
|
241
|
+
|
|
242
|
+
/** The set of Project builtin Agent ids (supplied along with the Project, cannot be deleted from Web). */
|
|
243
|
+
declare const BUILTIN_AGENT_IDS: readonly string[];
|
|
244
|
+
/** Agent initialization preset (only takes effect at initialization; ignored when loading an existing Agent). */
|
|
245
|
+
interface AgentPreset {
|
|
246
|
+
/** Display name written to system_config.yaml. */
|
|
247
|
+
name?: string;
|
|
248
|
+
/** Description written to system_config.yaml. */
|
|
249
|
+
description?: string;
|
|
250
|
+
/** Overrides the default AGENTS.md content. */
|
|
251
|
+
agentsMd?: string;
|
|
252
|
+
/** Skills installed at initialization (installs none by default). */
|
|
253
|
+
skills?: LibrarySkill[];
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* The preset list for a Project's builtin Agents (each initialized in turn when the Project is
|
|
257
|
+
* created; an existing Agent is never overwritten). The only builtin Agent is default_agent:
|
|
258
|
+
* installs every Skill in the library, with no preset AGENTS.md.
|
|
259
|
+
*/
|
|
260
|
+
declare function builtinProjectAgentPresets(): Array<{
|
|
261
|
+
agentId: string;
|
|
262
|
+
preset: AgentPreset;
|
|
263
|
+
}>;
|
|
264
|
+
|
|
265
|
+
type IdKind = "project_id" | "agent_id" | "skill_name";
|
|
266
|
+
declare function isValidId(id: string): boolean;
|
|
267
|
+
declare function assertValidId(kind: IdKind, id: string): void;
|
|
268
|
+
/** A loaded Agent State handle. */
|
|
269
|
+
interface AgentState {
|
|
270
|
+
root: string;
|
|
271
|
+
projectId: string;
|
|
272
|
+
agentId: string;
|
|
273
|
+
stateDir: string;
|
|
274
|
+
systemConfig: SystemConfig;
|
|
275
|
+
agentsMd: string;
|
|
276
|
+
}
|
|
277
|
+
interface SessionEnvironmentValues {
|
|
278
|
+
sessionId: string;
|
|
279
|
+
cwd: string;
|
|
280
|
+
/** The Agent id this Session belongs to (system Prompt placeholder {{AGENT_ID}}). */
|
|
281
|
+
agentId: string;
|
|
282
|
+
/** Absolute path to this Project's directory (system Prompt placeholder {{PROJECT_DIR}}; Agent State/scratchpad paths are derived from it). */
|
|
283
|
+
projectDir: string;
|
|
284
|
+
platform: string;
|
|
285
|
+
osVersion: string;
|
|
286
|
+
date: string;
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Loads or initializes Agent State.
|
|
290
|
+
*
|
|
291
|
+
* When root/project/agent are omitted, `resolveRoot()` and the default constants are used. If
|
|
292
|
+
* `system_config.yaml` doesn't exist, the directory is treated as empty and initialized;
|
|
293
|
+
* otherwise the existing content is loaded. `preset` only takes effect on the initialization
|
|
294
|
+
* path (name/description/AGENTS.md overrides and extra Skills) and is ignored when loading an
|
|
295
|
+
* existing Agent — existing config is never overwritten.
|
|
296
|
+
*/
|
|
297
|
+
declare function loadOrInitAgentState(opts?: {
|
|
298
|
+
agentId?: string;
|
|
299
|
+
projectId?: string;
|
|
300
|
+
root?: string;
|
|
301
|
+
preset?: AgentPreset;
|
|
302
|
+
}): Promise<AgentState>;
|
|
303
|
+
/**
|
|
304
|
+
* Initializes a Project's built-in Agent (the only built-in Agent: default_agent).
|
|
305
|
+
*
|
|
306
|
+
* Calls loadOrInitAgentState for each one: an Agent whose directory already exists (including a
|
|
307
|
+
* default_agent created earlier by the CLI) is only loaded, never overwritten (preset only
|
|
308
|
+
* takes effect on initialization). Returns the list of built-in Agent ids.
|
|
309
|
+
*/
|
|
310
|
+
declare function provisionProjectAgents(opts?: {
|
|
311
|
+
root?: string;
|
|
312
|
+
projectId?: string;
|
|
313
|
+
}): Promise<string[]>;
|
|
314
|
+
/**
|
|
315
|
+
* Installs a Skill into the target Agent: writes `skills/<name>/SKILL.md` verbatim (the full
|
|
316
|
+
* SKILL.md content including frontmatter, ensuring a trailing newline); if the directory
|
|
317
|
+
* already exists, it's overwritten (reinstalling = updating to the latest content). An optional
|
|
318
|
+
* icon.svg is written alongside SKILL.md; if this install doesn't
|
|
319
|
+
* include an icon, any old icon.svg is removed, preserving "overwrite update" semantics (the
|
|
320
|
+
* directory content matches the Skill being installed).
|
|
321
|
+
* Docs: /docs/skills § "Installation and storage".
|
|
322
|
+
*/
|
|
323
|
+
declare function installSkill(root: string, projectId: string, agentId: string, skill: {
|
|
324
|
+
name: string;
|
|
325
|
+
content: string;
|
|
326
|
+
icon?: string;
|
|
327
|
+
}): Promise<void>;
|
|
328
|
+
/** Uninstalls a Skill: deletes the entire `skills/<name>/` directory; idempotent, no error if it doesn't exist. */
|
|
329
|
+
declare function removeSkill(root: string, projectId: string, agentId: string, name: string): Promise<void>;
|
|
330
|
+
/** An installed Skill entry: frontmatter metadata (including an optional short description) + the optional icon.svg content in the directory. */
|
|
331
|
+
interface InstalledSkill extends SkillMetadata {
|
|
332
|
+
/** The raw content of `skills/<name>/icon.svg` (a custom icon copied alongside SKILL.md at install time); the field is omitted when missing (the frontend falls back to a default book icon). */
|
|
333
|
+
icon?: string;
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Lists the metadata of Skills installed on the target Agent: scans `skills/<name>/SKILL.md` and
|
|
337
|
+
* parses its frontmatter (optional fields like short_description(_zh) pass through as parsed),
|
|
338
|
+
* also reading the optional icon.svg content in the directory. Tolerant: a directory whose
|
|
339
|
+
* frontmatter fails to parse or is missing `name` falls back to
|
|
340
|
+
* `{ name: <directory name>, description: "", version: 1, updated: "" }`; a directory with no
|
|
341
|
+
* SKILL.md doesn't count as a Skill; returns [] if skills/ doesn't exist. Results are sorted by
|
|
342
|
+
* name (a stable order for both Prompt injection and API responses).
|
|
343
|
+
* Docs: /docs/skills § "Installation and storage".
|
|
344
|
+
*/
|
|
345
|
+
declare function listInstalledSkills(root: string, projectId: string, agentId: string): Promise<InstalledSkill[]>;
|
|
346
|
+
/**
|
|
347
|
+
* Skill metadata section: the replacement value for `{{SKILL_METADATA}}`, one line per Skill in
|
|
348
|
+
* the form `- \`name\` — description` (just the name when description is empty); an empty array
|
|
349
|
+
* returns an empty string. The full body is read by the model on demand via shell.
|
|
350
|
+
*/
|
|
351
|
+
declare function skillMetadataSection(skills: SkillMetadata[]): string;
|
|
352
|
+
/**
|
|
353
|
+
* Renders the complete runtime system Prompt: substitutes `AGENTS.md`, vault key names, Skill
|
|
354
|
+
* metadata, and the concrete Session runtime environment placeholders into the system Prompt
|
|
355
|
+
* template. The assembly layer only does placeholder substitution and adds no extra text —
|
|
356
|
+
* wrapper text such as `<developer_instructions>` and the # Vault / # Skills statements are
|
|
357
|
+
* written directly into the system Prompt template itself (the Prompt is fully
|
|
358
|
+
* transparent and editable via `system_config.yaml`). Other files in Agent State / Workspace are
|
|
359
|
+
* never auto-injected.
|
|
360
|
+
*
|
|
361
|
+
* `{{VAULT_KEYS}}` is replaced with the vault key-name list (an empty string if empty/not
|
|
362
|
+
* provided): this lets the model know which APIs requiring a key it can call; values are never
|
|
363
|
+
* injected. `{{SKILL_METADATA}}` is replaced with the installed Skills' metadata lines (an empty
|
|
364
|
+
* string if empty/not provided). A custom template that removes a placeholder gets no
|
|
365
|
+
* corresponding content injected.
|
|
366
|
+
* Docs: /docs/configuration § "System prompt placeholders".
|
|
367
|
+
*/
|
|
368
|
+
declare function assembleSystemPrompt(state: AgentState, sessionEnvironment?: SessionEnvironmentValues, vaultKeys?: string[], skillMetadata?: SkillMetadata[]): string;
|
|
369
|
+
/**
|
|
370
|
+
* Builds the `ToolConfig` needed by Environment from Agent State.
|
|
371
|
+
*
|
|
372
|
+
* Both builtin tools and MCP Server config are taken from `system_config.yaml`; falls back to the
|
|
373
|
+
* default config when builtin tools are missing.
|
|
374
|
+
*/
|
|
375
|
+
/**
|
|
376
|
+
* Filters builtin tool entries by the session model's type: entries with `forModel: "vision"` are
|
|
377
|
+
* only used for models that support images (vision models), `forModel: "text-only"` is only for
|
|
378
|
+
* text-only models (e.g. choosing between read_image / describe_image); unlabeled entries are
|
|
379
|
+
* available to all models.
|
|
380
|
+
* Docs: /docs/tools § "Image tools".
|
|
381
|
+
*/
|
|
382
|
+
declare function selectBuiltinToolsForModel(tools: ToolDefinitionConfig[], modelVision: boolean): ToolDefinitionConfig[];
|
|
383
|
+
declare function buildToolConfig(state: AgentState): ToolConfig;
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* Vault value length cap: since values are injected into the child-process environment, Linux
|
|
387
|
+
* caps a single env entry at roughly 128KB, and an oversized value would make every
|
|
388
|
+
* exec_command spawn for that Agent fail (E2BIG) — so it's rejected on the write side (core and
|
|
389
|
+
* the API layer share this same cap).
|
|
390
|
+
*/
|
|
391
|
+
declare const VAULT_VALUE_MAX_LENGTH = 8192;
|
|
392
|
+
/** Whether a vault key name is valid (shell environment variable name rules). */
|
|
393
|
+
declare function isValidVaultKey(key: string): boolean;
|
|
394
|
+
/** Validates a vault key name, throwing if invalid (core and the API layer share this same rule). */
|
|
395
|
+
declare function assertValidVaultKey(key: string): void;
|
|
396
|
+
/** Validates a vault value's length (see `VAULT_VALUE_MAX_LENGTH`), throwing if it exceeds the cap. */
|
|
397
|
+
declare function assertValidVaultValue(key: string, value: string): void;
|
|
398
|
+
/**
|
|
399
|
+
* Reads the Agent vault: returns an empty table if the file doesn't exist.
|
|
400
|
+
* A hand-edited file is filtered by the same rule as the write side: only string values are
|
|
401
|
+
* accepted (numbers/dates etc. are ignored), and key names must follow shell variable name rules
|
|
402
|
+
* (invalid keys are always ignored — otherwise they'd get injected into the Prompt/child-process
|
|
403
|
+
* environment, and an invalid key surfaced by a GET view would make a full-table PUT 400, leaving
|
|
404
|
+
* the vault page unable to add or remove any further entries).
|
|
405
|
+
*/
|
|
406
|
+
declare function loadAgentVault(root: string, projectId: string, agentId: string): Promise<Record<string, string>>;
|
|
407
|
+
/**
|
|
408
|
+
* Writes the full table to the Agent vault: validates all key names first; an empty table
|
|
409
|
+
* deletes the file (idempotent if it doesn't exist).
|
|
410
|
+
* The directory is created automatically if it doesn't exist (the vault can be configured even
|
|
411
|
+
* before the Agent is initialized).
|
|
412
|
+
*/
|
|
413
|
+
declare function saveAgentVault(root: string, projectId: string, agentId: string, vault: Record<string, string>): Promise<void>;
|
|
414
|
+
/**
|
|
415
|
+
* Writes or updates one vault entry (added if it doesn't exist, overwritten if it does).
|
|
416
|
+
* The key name must follow shell environment variable name rules (see `isValidVaultKey`), and the
|
|
417
|
+
* value length is constrained by `VAULT_VALUE_MAX_LENGTH`; throws if invalid. Returns the updated
|
|
418
|
+
* vault.
|
|
419
|
+
*/
|
|
420
|
+
declare function setVaultEntry(root: string, projectId: string, agentId: string, key: string, value: string): Promise<Record<string, string>>;
|
|
421
|
+
/**
|
|
422
|
+
* Removes one vault entry; idempotent if the key doesn't exist (no write happens). Once emptied,
|
|
423
|
+
* the whole .vault.toml is removed. Returns the updated vault.
|
|
424
|
+
*/
|
|
425
|
+
declare function removeVaultEntry(root: string, projectId: string, agentId: string, key: string): Promise<Record<string, string>>;
|
|
426
|
+
|
|
427
|
+
/** Directory name of the example Benchmark (the directory name is also its identifier). */
|
|
428
|
+
declare const EXAMPLE_BENCHMARK_ID = "example-benchmark";
|
|
429
|
+
/** Raw result of a single run (a runs element in scoreboard v2). */
|
|
430
|
+
interface ExampleRun {
|
|
431
|
+
score: number;
|
|
432
|
+
cost: number;
|
|
433
|
+
duration_ms: number;
|
|
434
|
+
session_id: string;
|
|
435
|
+
}
|
|
436
|
+
/**
|
|
437
|
+
* Builds the scoreboard object from raw runs data: each case's three metrics are the
|
|
438
|
+
* average of its runs, and each evaluation's metrics are the sum of its cases' averages
|
|
439
|
+
* (following the scoreboard v2 convention). Exported so tests can verify the numbers
|
|
440
|
+
* are self-consistent.
|
|
441
|
+
*/
|
|
442
|
+
declare function buildExampleScoreboard(): {
|
|
443
|
+
evaluations: Array<{
|
|
444
|
+
time: string;
|
|
445
|
+
version: number;
|
|
446
|
+
provider: string;
|
|
447
|
+
model_id: string;
|
|
448
|
+
summary_title: string;
|
|
449
|
+
summary: string;
|
|
450
|
+
score: number;
|
|
451
|
+
cost: number;
|
|
452
|
+
duration_ms: number;
|
|
453
|
+
cases: Array<{
|
|
454
|
+
case: string;
|
|
455
|
+
score: number;
|
|
456
|
+
cost: number;
|
|
457
|
+
duration_ms: number;
|
|
458
|
+
runs: ExampleRun[];
|
|
459
|
+
}>;
|
|
460
|
+
}>;
|
|
461
|
+
};
|
|
462
|
+
/**
|
|
463
|
+
* Provisions the example Benchmark: if `benchmarks/` already exists (the user already has a
|
|
464
|
+
* case library), does nothing; otherwise creates `benchmarks/example-benchmark/` (config, the
|
|
465
|
+
* two sample cases, and the scoreboard). Callers are restricted to the default_agent
|
|
466
|
+
* initialization path (see agent-state.ts).
|
|
467
|
+
*/
|
|
468
|
+
declare function provisionExampleBenchmark(root: string, projectId: string, agentId: string): Promise<void>;
|
|
469
|
+
|
|
470
|
+
/**
|
|
471
|
+
* GenerativeModel —— the SDK's LLM interface implementation.
|
|
472
|
+
*
|
|
473
|
+
* Responsibilities (protocol translation + streaming aggregation):
|
|
474
|
+
* 1. Merge a group of OmniMessages that **share the same role** into a single AgentHub `UniMessage`;
|
|
475
|
+
* 2. Issue the request via `AutoLLMClient.streamingResponseStateful` (stateful — AgentHub
|
|
476
|
+
* maintains history internally), translating streamed `UniEvent`s back into OmniMessages:
|
|
477
|
+
* - text/thinking/tool-call deltas → `partial_*` (before the first delta of each segment
|
|
478
|
+
* `yield` a `start`; after the segment ends `yield` a `stop`);
|
|
479
|
+
* - after a segment ends, append the full `model_msg` (thinking / text / tool_call);
|
|
480
|
+
* - a `token_usage` event_msg is produced **only on normal completion**
|
|
481
|
+
* (observability/Token).
|
|
482
|
+
* 3. Interruption/error handling: `finishInterrupted` first closes any open
|
|
483
|
+
* streaming segments and backfills the complete message, then the output ends — never
|
|
484
|
+
* leaking a malformed structure. This interface **never retries internally** — retryable
|
|
485
|
+
* errors (network/timeout/429/5xx, see `isRetryableError`) end with `timeout`; AgentHub
|
|
486
|
+
* JSON parse errors end with `malformed`; both are handed to `context_engine` to reconnect
|
|
487
|
+
* within the same run. User interruption ends with `aborted`; non-retryable errors
|
|
488
|
+
* (auth/parameters) end with `failed`.
|
|
489
|
+
*
|
|
490
|
+
* `context_engine` only consumes OmniMessage; all Uni* protocol details are encapsulated here.
|
|
491
|
+
* Docs: /docs/interfaces § "The built-in implementation: GenerativeModel".
|
|
492
|
+
*/
|
|
493
|
+
|
|
494
|
+
/**
|
|
495
|
+
* Groups a replayed, complete OmniMessage history into a sequence of UniMessages by
|
|
496
|
+
* **adjacent same-role** runs (used for the setHistory injection during Session recovery).
|
|
497
|
+
* One committed turn = a group of user-side input + a group of
|
|
498
|
+
* assistant output, matching exactly the adjacent user / assistant UniMessages in AgentHub history.
|
|
499
|
+
*/
|
|
500
|
+
declare function groupHistoryToUniMessages(history: OmniMessage[]): UniMessage[];
|
|
501
|
+
/**
|
|
502
|
+
* Merges a group of OmniMessages into **a single** UniMessage.
|
|
503
|
+
*
|
|
504
|
+
* Constraint: all messages in the array must share the same
|
|
505
|
+
* role; the role of the first payload is used as the UniMessage's role (a tool_call_output
|
|
506
|
+
* group has role "user"). Throws if roles are mixed.
|
|
507
|
+
*/
|
|
508
|
+
declare function mergeOmniToUniMessage(messages: OmniMessage[]): UniMessage;
|
|
509
|
+
/**
|
|
510
|
+
* Converts AgentHub `UsageMetadata` into PenguinHarness `TokenCounts`.
|
|
511
|
+
*
|
|
512
|
+
* Conversion rules (AgentHub UsageMetadata → OmniMessage TokenCounts, null treated as 0):
|
|
513
|
+
* - `cache_read = cached_tokens` (input tokens served from cache hits);
|
|
514
|
+
* - `cache_write = prompt_tokens` (input tokens on a cache miss);
|
|
515
|
+
* - `output = thoughts_tokens + response_tokens`;
|
|
516
|
+
* - `total = cache_read + cache_write + output`.
|
|
517
|
+
* That is, `input = cache_read + cache_write = cached_tokens + prompt_tokens`,
|
|
518
|
+
* and `total = input + output` (consistent with SKILL.md's input/output accounting).
|
|
519
|
+
*/
|
|
520
|
+
declare function usageToTokenCounts(usage: UsageMetadata): TokenCounts;
|
|
521
|
+
/**
|
|
522
|
+
* Streaming translator. Feed `UniEvent`s one at a time into `pushEvent`, which yields
|
|
523
|
+
* incremental OmniMessages (`partial_*`); after the stream ends, call `finish` to produce
|
|
524
|
+
* `stop`, the complete `model_msg`, and `token_usage`.
|
|
525
|
+
*
|
|
526
|
+
* Split into its own class to make unit testing easier (feed a constructed array of UniEvents,
|
|
527
|
+
* assert on emission order / aggregation / token counts).
|
|
528
|
+
* Docs: /docs/omni-message § "The streaming discipline".
|
|
529
|
+
*/
|
|
530
|
+
declare class EventTranslator {
|
|
531
|
+
private readonly toolCallIds;
|
|
532
|
+
/**
|
|
533
|
+
* tool_call_id uniqueness registry. By default each translator creates its own (unit tests /
|
|
534
|
+
* one-off translation); in production `GenerativeModel` injects a Session-level shared instance so
|
|
535
|
+
* the uniqueness scope spans Requests and survives compaction rebuilds.
|
|
536
|
+
*/
|
|
537
|
+
constructor(toolCallIds?: ToolCallIdAllocator);
|
|
538
|
+
private textStarted;
|
|
539
|
+
private thinkingStarted;
|
|
540
|
+
private toolStarted;
|
|
541
|
+
private activeToolCallId;
|
|
542
|
+
private textBuffer;
|
|
543
|
+
private thinkingBuffer;
|
|
544
|
+
private thinkingSignature;
|
|
545
|
+
private textPhase;
|
|
546
|
+
private textSignature;
|
|
547
|
+
/** Provider id keys saved in order of appearance, so complete tool_calls are emitted in a stable order. */
|
|
548
|
+
private toolOrder;
|
|
549
|
+
/** provider's original tool_call_id → the accumulator for the **latest** call under that id. */
|
|
550
|
+
private tools;
|
|
551
|
+
private finishReason;
|
|
552
|
+
/** Token usage for this request (a snapshot from the most recent usage report). */
|
|
553
|
+
private requestTokens;
|
|
554
|
+
/** Consumes one UniEvent, yielding 0..n streaming OmniMessages. */
|
|
555
|
+
pushEvent(event: UniEvent): Generator<OmniMessage>;
|
|
556
|
+
/**
|
|
557
|
+
* Stream-end finalization: first `yield` the `stop` and complete message for the text/thinking
|
|
558
|
+
* segments, then backfill partial(stop) + complete tool_call for tool_calls that **haven't
|
|
559
|
+
* been emitted eagerly yet** (i.e. the fallback case — no complete tool_call content item was
|
|
560
|
+
* received, only deltas). Tools already emitted eagerly in `pushEvent` are not repeated here.
|
|
561
|
+
*/
|
|
562
|
+
finish(): Generator<OmniMessage>;
|
|
563
|
+
/**
|
|
564
|
+
* Interruption finalization: even when interrupted or on error, close the structure
|
|
565
|
+
* as `start → delta → stop → complete message`. Closes any unclosed thinking/text segments and
|
|
566
|
+
* backfills their complete messages, then backfills partial(stop) + complete tool_call for
|
|
567
|
+
* tool_calls that only have deltas and were never emitted eagerly. All backfilled messages are
|
|
568
|
+
* uniformly tagged with the interruption `stopReason` (`aborted` / `timeout` / `failed`), to
|
|
569
|
+
* distinguish them from normal completion (`completed`).
|
|
570
|
+
*
|
|
571
|
+
* Differs from `finish`: doesn't read `finish_reason`, and doesn't produce `token_usage` (an
|
|
572
|
+
* interrupted Request has no usage to report); backfilled incomplete tool_calls carry the
|
|
573
|
+
* interruption stop_reason, so `context_engine` won't dispatch them for execution.
|
|
574
|
+
*/
|
|
575
|
+
finishInterrupted(stopReason: StopReason): Generator<OmniMessage>;
|
|
576
|
+
/**
|
|
577
|
+
* Eagerly emits the finalization of a tool_call: partial(stop) (without name) + complete
|
|
578
|
+
* tool_call. Marks `emitted` to prevent duplicate emission in finish. `stopReason` defaults to
|
|
579
|
+
* `completed` (a normal request); when called during interruption finalization
|
|
580
|
+
* (`finishInterrupted`), the interruption reason is passed in, letting `context_engine`
|
|
581
|
+
* distinguish "a real tool request" from "an incomplete tool_call backfilled to close the
|
|
582
|
+
* structure on interruption" by stop_reason, and dispatch only the former.
|
|
583
|
+
*/
|
|
584
|
+
private emitCompleteTool;
|
|
585
|
+
/**
|
|
586
|
+
* Closes out the currently buffered thinking segment and appends the complete thinking
|
|
587
|
+
* message, then clears the buffer and resets the start flag. May be called before eagerly
|
|
588
|
+
* emitting the first complete tool_call (`pushEvent`) or at stream end (`finish`), which
|
|
589
|
+
* guarantees the complete-message order is thinking → text → tool_call.
|
|
590
|
+
*
|
|
591
|
+
* "Flush then reset" rather than a one-shot guard: once the buffer is cleared, a repeated call
|
|
592
|
+
* is a no-op (each segment is emitted exactly once); if the model outputs new thinking after a
|
|
593
|
+
* tool_call (interleaved/multi-segment models), that new segment accumulates again and gets
|
|
594
|
+
* correctly flushed at the next tool_call or `finish`, without being lost.
|
|
595
|
+
*
|
|
596
|
+
* The complete thinking message passes through the given stop_reason just like partial(stop)
|
|
597
|
+
* (aligned with flushText — streamed concatenation == complete message): at type boundaries the
|
|
598
|
+
* caller passes completed (the stop reason belongs to the following tool_call/text);
|
|
599
|
+
* finish/finishInterrupted follow the actual end reason.
|
|
600
|
+
*/
|
|
601
|
+
private flushThinking;
|
|
602
|
+
/**
|
|
603
|
+
* Closes out the currently buffered text segment and appends the complete text message, then
|
|
604
|
+
* clears the buffer and resets the start flag. Uses the same "flush then reset" approach as
|
|
605
|
+
* `flushThinking` to support new text segments after a tool_call. When emitted before the
|
|
606
|
+
* first complete tool_call, finish_reason is unknown and the caller passes completed; when
|
|
607
|
+
* emitted in `finish`, the final `omniStopReason()` is passed (consistent with prior behavior).
|
|
608
|
+
*/
|
|
609
|
+
private flushText;
|
|
610
|
+
/** Whether finish_reason (the terminal event) has been received: signals a fully delivered response (see the defensive branch in streamGenerate). */
|
|
611
|
+
sawFinishReason(): boolean;
|
|
612
|
+
/** Token usage for this request (read after finish). */
|
|
613
|
+
getRequestTokens(): TokenCounts;
|
|
614
|
+
private ensureTool;
|
|
615
|
+
/**
|
|
616
|
+
* Create an accumulator for a new call: the emitted id is made unique via the Session-level registry
|
|
617
|
+
* (kept as-is when the provider id is free, with a `#n` suffix on collision). Creating again under the
|
|
618
|
+
* same provider id (another call with a duplicate id) replaces the old Map entry — the old call has
|
|
619
|
+
* finished emitting, so later inbound events are attributed to the latest call.
|
|
620
|
+
*/
|
|
621
|
+
private createTool;
|
|
622
|
+
private usageOnce;
|
|
623
|
+
/**
|
|
624
|
+
* Converts an AgentHub finish_reason into an OmniMessage stop_reason (the five-value protocol).
|
|
625
|
+
* "stop", "tool_call", and null are treated as completed; length or unknown reasons map to failed.
|
|
626
|
+
*/
|
|
627
|
+
private omniStopReason;
|
|
628
|
+
}
|
|
629
|
+
/**
|
|
630
|
+
* One-shot translation: folds a batch of UniEvents into an OmniMessage sequence (including
|
|
631
|
+
* complete messages and token_usage). A pure function for easy unit testing; the live streaming
|
|
632
|
+
* path is wired up by `GenerativeModel.streamGenerate`.
|
|
633
|
+
*
|
|
634
|
+
* @param events The event sequence
|
|
635
|
+
* @param sessionTokensBefore The session's cumulative tokens before this translation (used to produce token_usage.session)
|
|
636
|
+
* @returns `{ messages, requestTokens, sessionTokens }`
|
|
637
|
+
*/
|
|
638
|
+
declare function translateEvents(events: UniEvent[], sessionTokensBefore?: TokenCounts): {
|
|
639
|
+
messages: OmniMessage[];
|
|
640
|
+
requestTokens: TokenCounts;
|
|
641
|
+
sessionTokens: TokenCounts;
|
|
642
|
+
};
|
|
643
|
+
/**
|
|
644
|
+
* Determines whether an error is an AgentHub / Provider response JSON parse error.
|
|
645
|
+
*
|
|
646
|
+
* AgentHub uses `JSON.parse` internally to parse response bodies, and a parse failure throws a
|
|
647
|
+
* `SyntaxError`; hence we judge directly by exception type (the `name` check also covers
|
|
648
|
+
* cross-realm or deserialization-reconstructed errors, and we probe down the `cause` chain for
|
|
649
|
+
* wrapped errors). This is not an auth/parameter failure but an incomplete LLM Request, and
|
|
650
|
+
* should end with `malformed` and be handed to the engine to retry.
|
|
651
|
+
*/
|
|
652
|
+
declare function isMalformedJsonParseError(error: unknown): boolean;
|
|
653
|
+
/**
|
|
654
|
+
* Determines whether an error is AgentHub's "incomplete stream" validation error: when a
|
|
655
|
+
* server/proxy terminates the stream early **cleanly** at an event boundary (no network error
|
|
656
|
+
* thrown), AgentHub's `_validateLastEvent` reports the missing or incomplete final event as a
|
|
657
|
+
* plain `Error` ("Streaming response yielded no events" / "Last event must carry
|
|
658
|
+
* usage_metadata|finish_reason"). This is not an auth/parameter failure but an incomplete LLM
|
|
659
|
+
* Request, and should end with `malformed` and be handed to the engine to reconnect and retry.
|
|
660
|
+
* AgentHub doesn't provide an error type for this, so we match by message prefix
|
|
661
|
+
* (@prismshadow/agenthub 0.3.x), probing down the `cause` chain.
|
|
662
|
+
*/
|
|
663
|
+
declare function isIncompleteStreamError(error: unknown): boolean;
|
|
664
|
+
/**
|
|
665
|
+
* Determines whether an error is retryable.
|
|
666
|
+
*
|
|
667
|
+
* Retryable: network errors, timeouts, connection reset, HTTP 429 / 5xx.
|
|
668
|
+
* Not retryable: HTTP 4xx auth/parameter errors (401/403/400/404, etc.).
|
|
669
|
+
* JSON parse errors are classified separately as `malformed` by `isMalformedJsonParseError`.
|
|
670
|
+
*
|
|
671
|
+
* Since AgentHub doesn't guarantee the shape of error objects, this uses a lenient check: first
|
|
672
|
+
* the status code, then error codes / message keywords. When undeterminable, treat it as
|
|
673
|
+
* **non-retryable** to avoid pointless retries.
|
|
674
|
+
*/
|
|
675
|
+
declare function isRetryableError(error: unknown): boolean;
|
|
676
|
+
/**
|
|
677
|
+
* A stateful LLM object attached to a Session. AgentHub's `streamingResponseStateful` maintains
|
|
678
|
+
* conversation history internally; this class is only responsible for protocol translation,
|
|
679
|
+
* streaming aggregation, and token accumulation. **It never retries internally** — retries are
|
|
680
|
+
* handled by `context_engine`.
|
|
681
|
+
*/
|
|
682
|
+
declare class GenerativeModel implements LLMInterface {
|
|
683
|
+
private readonly client;
|
|
684
|
+
private readonly uniConfig;
|
|
685
|
+
/** Streaming idle timeout (milliseconds); <= 0 disables it. A timeout is treated as needing reconnection. */
|
|
686
|
+
private readonly requestTimeoutMs;
|
|
687
|
+
/**
|
|
688
|
+
* tool_call_id uniqueness registry (see tool-call-ids.ts): when a name-as-id provider (e.g. Gemini)
|
|
689
|
+
* calls the same tool repeatedly, it assigns a `#n` suffix to later calls so engine pairing and the
|
|
690
|
+
* frontend tool cards don't collide on id. Injected via config so it can be shared across the new
|
|
691
|
+
* instance rebuilt on compaction; defaults to a fresh one.
|
|
692
|
+
*/
|
|
693
|
+
private readonly toolCallIds;
|
|
694
|
+
/** Cumulative session tokens. */
|
|
695
|
+
sessionTokens: TokenCounts;
|
|
696
|
+
constructor(config: GenerativeModelConfig);
|
|
697
|
+
/**
|
|
698
|
+
* Streaming generation (a single attempt, no internal retry). Merges
|
|
699
|
+
* `params.newMessages` into one UniMessage to issue a stateful request, translating streamed
|
|
700
|
+
* UniEvents into OmniMessages.
|
|
701
|
+
*
|
|
702
|
+
* **Never throws to `context_engine`**: whether it ends normally or is interrupted/errors out,
|
|
703
|
+
* every `partial_*` segment is closed as `start → delta → stop → complete message`,
|
|
704
|
+
* and the terminal state is then returned as `LLMOutcome`:
|
|
705
|
+
* - **Normal completion**: `finish()` closes out and produces `token_usage` (usage is only
|
|
706
|
+
* produced in this case) → `completed`;
|
|
707
|
+
* - **Idle timeout / network drop** (retryable errors like network/429/5xx):
|
|
708
|
+
* `finishInterrupted("timeout")` closes out, produces no usage → `timeout`, reconnected by
|
|
709
|
+
* `context_engine` within the same run;
|
|
710
|
+
* - **AgentHub JSON parse error**: `finishInterrupted("malformed")` closes out, produces no
|
|
711
|
+
* usage → `malformed`, likewise reconnected by `context_engine` within the same run;
|
|
712
|
+
* - **User interruption**: `finishInterrupted("aborted")` closes out, produces no usage →
|
|
713
|
+
* `aborted`;
|
|
714
|
+
* - **Other non-retryable errors** (auth/parameters etc.): `finishInterrupted("failed")`
|
|
715
|
+
* closes out, produces no usage → `failed` (carrying `message`), handed to
|
|
716
|
+
* `context_engine` to stop and return control to the user.
|
|
717
|
+
*
|
|
718
|
+
* Timeout detection: the idle timer resets on every event received; once idle exceeds
|
|
719
|
+
* `requestTimeoutMs`, the underlying stream is aborted and handled as needing reconnection
|
|
720
|
+
* (merged with user interruption into a single internal AbortController).
|
|
721
|
+
*/
|
|
722
|
+
streamGenerate(params: GenerativeModelParameters): AsyncGenerator<OmniMessage, LLMOutcome>;
|
|
723
|
+
/**
|
|
724
|
+
* Injects the replayed history in one shot when resuming a Session: converts the complete
|
|
725
|
+
* OmniMessage history, grouped by adjacent same role, into
|
|
726
|
+
* AgentHub UniMessages and calls AgentHub's setHistory, so subsequent Requests continue from a
|
|
727
|
+
* history exactly matching the original conversation. **Called only once, on a fresh context
|
|
728
|
+
* object, during resumption**; not used during normal operation, where the incremental context
|
|
729
|
+
* is maintained by AgentHub itself.
|
|
730
|
+
* Docs: /docs/sessions-and-traces § "Session recovery".
|
|
731
|
+
*/
|
|
732
|
+
setHistory(history: OmniMessage[]): void;
|
|
733
|
+
/**
|
|
734
|
+
* Opens the underlying AgentHub stream (a testing seam): defaults to
|
|
735
|
+
* `streamingResponseStateful`; unit tests can subclass and override this method, feeding in a
|
|
736
|
+
* controlled UniEvent stream to verify the outcome classification for timeout/network
|
|
737
|
+
* drop/interruption/error (without a real API).
|
|
738
|
+
*/
|
|
739
|
+
protected openStream(uniMessage: UniMessage, signal: AbortSignal): AsyncIterable<UniEvent>;
|
|
740
|
+
}
|
|
741
|
+
/** Maps a ThinkingLevelName to the AgentHub ThinkingLevel enum; returns undefined if not found. */
|
|
742
|
+
declare function mapThinkingLevel(name: ThinkingLevelName | undefined): ThinkingLevel | undefined;
|
|
743
|
+
/** Maps ToolDefinition[] to AgentHub ToolSchema[]. */
|
|
744
|
+
declare function toolDefinitionsToSchemas(tools: ToolDefinition[]): ToolSchema[];
|
|
745
|
+
/** Pre-builds UniConfig from GenerativeModelConfig (called once at construction time). */
|
|
746
|
+
declare function buildUniConfig(config: GenerativeModelConfig): UniConfig;
|
|
747
|
+
|
|
748
|
+
declare class Environment implements EnvironmentInterface {
|
|
749
|
+
private readonly workspaceDir;
|
|
750
|
+
private readonly toolConfig;
|
|
751
|
+
/** Assembled built-in tools: tool name -> BuiltinTool. Only tools supported by the registry and present in config. */
|
|
752
|
+
private readonly tools;
|
|
753
|
+
/** Long-running command session registry: constructed within this Environment and shared between exec_command / input_command. */
|
|
754
|
+
private readonly commandSessions;
|
|
755
|
+
/** Background subagent session registry: constructed within this Environment and shared between run_subagent / input_subagent. */
|
|
756
|
+
private readonly subagentSessions;
|
|
757
|
+
constructor(config: EnvironmentConfig);
|
|
758
|
+
/** Releases runtime resources held by Environment: finalizes all managed background sessions (command and subagent). Idempotent. */
|
|
759
|
+
dispose(): void;
|
|
760
|
+
/**
|
|
761
|
+
* Lists tools available to the current Session, for context_engine to initialize GenerativeModel.
|
|
762
|
+
* Only lists tools that have been assembled (i.e. supported by the registry) — tool names
|
|
763
|
+
* unrecognized in config are not exposed to the LLM (consistent with the constructor);
|
|
764
|
+
* the definition (description/parameters) treats **the config entry as the single source of
|
|
765
|
+
* truth** — factories must not rewrite the definition at runtime; where a differentiated
|
|
766
|
+
* implementation is needed, use a separate explicit tool-name entry with a `forModel`
|
|
767
|
+
* annotation (e.g. read_image / describe_image).
|
|
768
|
+
* Only exposes `{name, description, parameters}`, dropping permission/maxOutputLength.
|
|
769
|
+
* MCP Server config flows into Environment via toolConfig; enumerating concrete MCP tools
|
|
770
|
+
* is left to a later adapter layer.
|
|
771
|
+
*/
|
|
772
|
+
listTools(): Promise<ToolDefinition[]>;
|
|
773
|
+
/** Looks up a tool's permission level (for the frontend's permission-mode decisions); returns undefined for an unknown tool. */
|
|
774
|
+
toolPermission(name: string): ToolPermission | undefined;
|
|
775
|
+
/**
|
|
776
|
+
* Executes an approved tool call, streaming `partial_tool_call_output` and a final
|
|
777
|
+
* `tool_call_output`; nested messages carrying origin pass through unchanged. Dispatches by
|
|
778
|
+
* looking up the tool name; any exception collapses into an explanatory output — never throws.
|
|
779
|
+
*
|
|
780
|
+
* The priority for deciding stop_reason is: user interruption > timeout > tool throw > tool
|
|
781
|
+
* self-report. Interruption is determined by the `signal` held by Environment, and is
|
|
782
|
+
* compatible with both a tool self-reporting aborted and an AbortError raised by the
|
|
783
|
+
* interruption. An internal abort raised by a timeout does not count as a user interruption —
|
|
784
|
+
* it's finalized as failed, with the timeout reason written into the output.
|
|
785
|
+
* Docs: /docs/tools § "Execution contract".
|
|
786
|
+
*/
|
|
787
|
+
executeTool(request: ToolExecutionRequest): AsyncGenerator<OmniMessage>;
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
/**
|
|
791
|
+
* Built-in tool registry —— maps tool names to BuiltinTool factories.
|
|
792
|
+
*
|
|
793
|
+
* Environment uses this table to assemble entries from ToolConfig into BuiltinTool instances:
|
|
794
|
+
* a tool is only assembled if its name is in the table (i.e. a supported built-in tool); the
|
|
795
|
+
* description/parameters/permission/maxOutputLength from config are injected into the tool's
|
|
796
|
+
* `definition` by each factory.
|
|
797
|
+
* When adding a new built-in tool, just register one factory entry here — no changes to
|
|
798
|
+
* Environment needed.
|
|
799
|
+
*
|
|
800
|
+
* Docs: packages/docs/content/tools.{zh,en}.md (site path /docs/tools) documents every
|
|
801
|
+
* built-in tool and the approval flow — keep the page in sync when this table changes.
|
|
802
|
+
*/
|
|
803
|
+
|
|
804
|
+
/**
|
|
805
|
+
* A factory that constructs a BuiltinTool instance from a tool config entry; optionally
|
|
806
|
+
* receives runtime services injected by Environment.
|
|
807
|
+
* Most tools ignore `services`; only a few (e.g. `run_subagent`) use it.
|
|
808
|
+
*/
|
|
809
|
+
type BuiltinToolFactory = (definition: ToolDefinitionConfig, services?: EnvironmentServices) => BuiltinTool;
|
|
810
|
+
/** Tool name -> factory. */
|
|
811
|
+
declare const BUILTIN_TOOL_FACTORIES: Record<string, BuiltinToolFactory>;
|
|
812
|
+
|
|
813
|
+
/** Tool name constant (used only inside this tool module, not exposed to Environment). */
|
|
814
|
+
declare const EXEC_COMMAND_NAME = "exec_command";
|
|
815
|
+
/**
|
|
816
|
+
* exec_command built-in tool: parses arguments, resolves workdir, and delegates to
|
|
817
|
+
* `CommandSessionManager` to spawn the process and collect output.
|
|
818
|
+
* `definition` is overridden by Environment at construction time with the matching entry
|
|
819
|
+
* from ToolConfig (description/parameters/permission/limits).
|
|
820
|
+
* `services.commandSessions` is injected by Environment (shares the same registry with
|
|
821
|
+
* input_command).
|
|
822
|
+
*/
|
|
823
|
+
declare function createExecCommandTool(definition: ToolDefinitionConfig, services?: EnvironmentServices): BuiltinTool;
|
|
824
|
+
|
|
825
|
+
/** Tool name constant. */
|
|
826
|
+
declare const INPUT_COMMAND_NAME = "input_command";
|
|
827
|
+
declare function createInputCommandTool(definition: ToolDefinitionConfig, services?: EnvironmentServices): BuiltinTool;
|
|
828
|
+
|
|
829
|
+
/** Tool name constant (used only within this tool module, never exposed to Environment). */
|
|
830
|
+
declare const SUBAGENT_NAME = "run_subagent";
|
|
831
|
+
/** Builds run_subagent's BuiltinTool from tool config + injected services. */
|
|
832
|
+
declare function createSubagentTool(definition: ToolDefinitionConfig, services?: EnvironmentServices): BuiltinTool;
|
|
833
|
+
|
|
834
|
+
/** Tool name constant. */
|
|
835
|
+
declare const INPUT_SUBAGENT_NAME = "input_subagent";
|
|
836
|
+
declare function createInputSubagentTool(definition: ToolDefinitionConfig, services?: EnvironmentServices): BuiltinTool;
|
|
837
|
+
|
|
838
|
+
interface WriterOptions {
|
|
839
|
+
/** Trace root directory, typically `<agent>/traces`. */
|
|
840
|
+
tracesDir: string;
|
|
841
|
+
/** Current Session id, written into the file name. */
|
|
842
|
+
sessionId: string;
|
|
843
|
+
/** The time used to derive the date subdirectory; defaults to `new Date()`. */
|
|
844
|
+
date?: Date;
|
|
845
|
+
/**
|
|
846
|
+
* Directly specifies the date subdirectory name (used when Session resumption continues
|
|
847
|
+
* writing to the original file: the Trace file follows the context, not the date); takes
|
|
848
|
+
* priority over `date`.
|
|
849
|
+
*/
|
|
850
|
+
dateDir?: string;
|
|
851
|
+
/** Starting Trace index (used when Session resumption continues the original index); defaults to 1. */
|
|
852
|
+
startIndex?: number;
|
|
853
|
+
}
|
|
854
|
+
/**
|
|
855
|
+
* append-only JSONL Trace writer.
|
|
856
|
+
*
|
|
857
|
+
* Single-writer scenario (MVP): concurrency safety isn't required, but every write uses
|
|
858
|
+
* `appendFile` (O_APPEND) rather than caching a file handle and seeking to write, avoiding
|
|
859
|
+
* overwriting existing content; this also removes the need for an explicit close.
|
|
860
|
+
*/
|
|
861
|
+
declare class Writer {
|
|
862
|
+
private readonly tracesDir;
|
|
863
|
+
private readonly sessionId;
|
|
864
|
+
private readonly dateDir;
|
|
865
|
+
/** Current Trace index, starting at 1; incremented by `rotate()`. */
|
|
866
|
+
private index;
|
|
867
|
+
/** Set true once the date directory has been created for the current file, to avoid a redundant mkdir. */
|
|
868
|
+
private ensuredDirForIndex;
|
|
869
|
+
constructor(opts: WriterOptions);
|
|
870
|
+
/** Absolute path of the current Trace file. */
|
|
871
|
+
currentPath(): string;
|
|
872
|
+
/**
|
|
873
|
+
* Appends one message. Only written if it's a recordable message; streaming `partial_*` is
|
|
874
|
+
* skipped. `mkdir -p`s the date directory on the first write to the current file.
|
|
875
|
+
*/
|
|
876
|
+
write(msg: OmniMessage): Promise<void>;
|
|
877
|
+
/** Writes multiple messages in sequence. */
|
|
878
|
+
writeAll(msgs: OmniMessage[]): Promise<void>;
|
|
879
|
+
/**
|
|
880
|
+
* Aggregates a message stream mixed with streaming `partial_*` into complete messages first,
|
|
881
|
+
* then writes them per the `write` convention. A convenience helper: `write` skips partial_*
|
|
882
|
+
* by default (the producer will already append the complete message), so this method is only
|
|
883
|
+
* needed when reconstructing a complete context from raw streaming fragments.
|
|
884
|
+
*/
|
|
885
|
+
aggregateAndWrite(msgs: OmniMessage[]): Promise<void>;
|
|
886
|
+
/**
|
|
887
|
+
* Starts a new Trace file: increments the index, so the next `write` goes to the new file.
|
|
888
|
+
* Used to split into a separate file when the context is compacted and a new context segment is produced.
|
|
889
|
+
* Docs: /docs/sessions-and-traces § "Trace design".
|
|
890
|
+
*/
|
|
891
|
+
rotate(): Promise<void>;
|
|
892
|
+
}
|
|
893
|
+
/** Parses a Trace file line by line (ignoring blank lines), for testing and later reads. */
|
|
894
|
+
declare function readTrace(path: string): Promise<OmniMessage[]>;
|
|
895
|
+
|
|
896
|
+
/** Replay result: all the state needed to resume a Session. */
|
|
897
|
+
interface ResumeResult {
|
|
898
|
+
/** Committed history (complete model_msg, in order), injected in one shot via setHistory; empty on compaction closure. */
|
|
899
|
+
history: CompleteModelMessage[];
|
|
900
|
+
/**
|
|
901
|
+
* Pending input (carry-over): resent alongside new input with the first `run` after resume.
|
|
902
|
+
* Already includes pairing-backfill placeholders — placeholders exist only in memory
|
|
903
|
+
* (synthesized carry-over is never written to Trace) and are resynthesized on each resume.
|
|
904
|
+
*/
|
|
905
|
+
carryOver: OmniMessage[];
|
|
906
|
+
/** Compaction closure (file-level): this file's context is fully closed; resume starts a new, empty context. */
|
|
907
|
+
contextClosed: boolean;
|
|
908
|
+
/** Compaction closure in summarize mode: the reconstructed `<context_summary>` summary, prepended to the next run's input. */
|
|
909
|
+
pendingSummary?: OmniMessage;
|
|
910
|
+
/** Session-level cumulative Token carry-over (the session value from the last token_usage). */
|
|
911
|
+
sessionTokens: TokenCounts;
|
|
912
|
+
/** The request.total from the last token_usage (context usage figure). */
|
|
913
|
+
lastRequestTotal: number;
|
|
914
|
+
/** Session cumulative turn count carry-over (count of completed requests). */
|
|
915
|
+
sessionTurns: number;
|
|
916
|
+
/** Rendering view: this context's complete model_msg plus key event_msg entries (including interrupted turns and their markers); empty on compaction closure. */
|
|
917
|
+
renderMessages: OmniMessage[];
|
|
918
|
+
/** The file's first session_meta; null if missing (unresumable — the caller reports the error). */
|
|
919
|
+
meta: SessionMetaMessage | null;
|
|
920
|
+
}
|
|
921
|
+
/**
|
|
922
|
+
* Parse Trace JSONL content. Tolerates a **truncated last line** left behind by an abnormal
|
|
923
|
+
* process exit (that line is ignored); corruption in the middle is outside the crash window
|
|
924
|
+
* (append-only, single writer), so it throws loudly.
|
|
925
|
+
*/
|
|
926
|
+
declare function parseTraceLines(content: string): OmniMessage[];
|
|
927
|
+
/** Read and parse a Trace file (tolerates a truncated last line). */
|
|
928
|
+
declare function readTraceTolerant(path: string): Promise<OmniMessage[]>;
|
|
929
|
+
/** A located Trace file: its path, containing date-directory name, and index. */
|
|
930
|
+
interface LocatedTraceFile {
|
|
931
|
+
path: string;
|
|
932
|
+
dateDir: string;
|
|
933
|
+
index: number;
|
|
934
|
+
}
|
|
935
|
+
/**
|
|
936
|
+
* Locate the **highest-index** Trace file for a Session (one Trace file corresponds to one
|
|
937
|
+
* complete model context). Scans `<tracesDir>/<yyyy-mm-dd>/<sessionId>_<index3>.jsonl`; returns
|
|
938
|
+
* null if no match is found.
|
|
939
|
+
*/
|
|
940
|
+
declare function findLatestTraceFile(tracesDir: string, sessionId: string): Promise<LocatedTraceFile | null>;
|
|
941
|
+
/**
|
|
942
|
+
* The id of the most recent Session under this Agent, determined by the timestamp embedded in
|
|
943
|
+
* session_id (ids are zero-padded, so lexical order equals chronological order). Returns null if
|
|
944
|
+
* there are no Sessions.
|
|
945
|
+
*/
|
|
946
|
+
declare function latestSessionId(tracesDir: string): Promise<string | null>;
|
|
947
|
+
/**
|
|
948
|
+
* Replay a Trace file (the current context), reconstructing history and carry-over input.
|
|
949
|
+
* Input is the message sequence parsed by `readTraceTolerant`.
|
|
950
|
+
*/
|
|
951
|
+
declare function resumeTrace(messages: OmniMessage[]): ResumeResult;
|
|
952
|
+
|
|
953
|
+
/** Trace sink: `write` a complete/event/meta message; `rotate` starts a new file (compaction splits files). */
|
|
954
|
+
interface TraceSink {
|
|
955
|
+
write(msg: OmniMessage): Promise<void>;
|
|
956
|
+
/** Optional: start a new Trace file (index+1), used to record the new model context after compaction. */
|
|
957
|
+
rotate?(): Promise<void>;
|
|
958
|
+
}
|
|
959
|
+
/**
|
|
960
|
+
* Resolved context compaction settings (defaults filled in by the composition layer).
|
|
961
|
+
* Docs: /docs/agent-loop § "Compaction".
|
|
962
|
+
*/
|
|
963
|
+
interface CompactionSettings {
|
|
964
|
+
/** Context token threshold (uses the most recent token_usage's request.total); <=0 disables it. */
|
|
965
|
+
maxContextLength: number;
|
|
966
|
+
/** Session cumulative turn threshold (counted per LLM Request, across Tasks); <=0 means no limit. */
|
|
967
|
+
maxSessionTurns: number;
|
|
968
|
+
mode: CompactionMode;
|
|
969
|
+
/** Prompt used for summarize compaction. */
|
|
970
|
+
prompt: string;
|
|
971
|
+
}
|
|
972
|
+
/**
|
|
973
|
+
* Options for `run`.
|
|
974
|
+
* Docs: /docs/agent-loop § "Inputs and outputs".
|
|
975
|
+
*/
|
|
976
|
+
interface RunOptions {
|
|
977
|
+
/** Abort signal (e.g. Ctrl-C). */
|
|
978
|
+
signal?: AbortSignal;
|
|
979
|
+
/** Per-tool approval callback; defaults to denying everything (conservative, to avoid accidental approval when unattended). */
|
|
980
|
+
approve?: ApproveFn;
|
|
981
|
+
}
|
|
982
|
+
/**
|
|
983
|
+
* Engine initial state (used for Session resumption): derived by replaying Trace, so the
|
|
984
|
+
* resumed engine behaves the same as before the process
|
|
985
|
+
* exited. Not passed when creating a normal new Session.
|
|
986
|
+
*/
|
|
987
|
+
interface EngineInitialState {
|
|
988
|
+
/** Pending input (carry-over): resent alongside new input on the first `run` after resumption (synthetic placeholders exist only in memory, never written to Trace). */
|
|
989
|
+
carryOver?: OmniMessage[];
|
|
990
|
+
/** Summary recovered from a completed summarize compaction: used as the prefix of the next `run` input (merged with the user Prompt). */
|
|
991
|
+
pendingSummary?: OmniMessage;
|
|
992
|
+
/** Carried-over Session cumulative turn count. */
|
|
993
|
+
sessionTurns?: number;
|
|
994
|
+
/** Carried-over Session cumulative token counts (handed to the new object when compaction swaps it in). */
|
|
995
|
+
sessionTokens?: TokenCounts;
|
|
996
|
+
/** Most recent token_usage's request.total (the context usage figure, keeps compaction threshold checks continuous). */
|
|
997
|
+
lastRequestTotal?: number;
|
|
998
|
+
/** Recovered from a completed compaction: the context is already closed, so rotate the Trace file (index+1, writing session_meta) before the first write. */
|
|
999
|
+
pendingTraceRotation?: boolean;
|
|
1000
|
+
}
|
|
1001
|
+
interface ContextEngineDeps {
|
|
1002
|
+
llm: LLMInterface;
|
|
1003
|
+
environment: EnvironmentInterface;
|
|
1004
|
+
/** Optional Trace writer; the writer is responsible for filtering out streaming partial_* messages. */
|
|
1005
|
+
trace?: TraceSink;
|
|
1006
|
+
/** Engine initial state (derived by replaying Trace on Session resumption). */
|
|
1007
|
+
initialState?: EngineInitialState;
|
|
1008
|
+
/** Maximum LLM turns for a single Task. Defaults to 100. */
|
|
1009
|
+
maxTurns?: number;
|
|
1010
|
+
/** Maximum automatic retries for LLM timeout/reconnect within a single run. Defaults to 2. */
|
|
1011
|
+
maxReconnects?: number;
|
|
1012
|
+
/** Linear backoff base (ms) before each reconnect retry; actual backoff = base × retry number. Defaults to 250. */
|
|
1013
|
+
reconnectBackoffMs?: number;
|
|
1014
|
+
/**
|
|
1015
|
+
* Creates a new LLM object after compaction (a fresh model context); the argument is the
|
|
1016
|
+
* current Session cumulative token counts, for the new object to carry forward
|
|
1017
|
+
* (token_usage.session stays continuous across compaction). Context compaction is
|
|
1018
|
+
* unavailable if this is not provided.
|
|
1019
|
+
*/
|
|
1020
|
+
createLLM?: (sessionTokens: TokenCounts) => LLMInterface;
|
|
1021
|
+
/** Context compaction settings; only takes effect if provided together with `createLLM`. */
|
|
1022
|
+
compaction?: CompactionSettings;
|
|
1023
|
+
/** This Session's session_meta message; written at the start of the new Trace file after compaction splits it. */
|
|
1024
|
+
sessionMeta?: OmniMessage;
|
|
1025
|
+
}
|
|
1026
|
+
/** Whether compaction is possible; when not `ok`, `compact()` is a no-op and yields no messages (see ContextEngine.compactability). */
|
|
1027
|
+
type CompactAvailability = "ok" | "unsupported" | "empty" | "just_compacted";
|
|
1028
|
+
declare class ContextEngine {
|
|
1029
|
+
private readonly deps;
|
|
1030
|
+
private readonly maxTurns;
|
|
1031
|
+
private readonly maxReconnects;
|
|
1032
|
+
private readonly reconnectBackoffMs;
|
|
1033
|
+
/** Interruption cleanup: content to resend generated when the previous run was aborted, held on the engine across runs. */
|
|
1034
|
+
private pendingCarryOver;
|
|
1035
|
+
/** Current LLM object; swapped for a new one created by `createLLM` after a successful compaction (a fresh model context). */
|
|
1036
|
+
private llm;
|
|
1037
|
+
/** Session cumulative turn count: counted per LLM Request that produces token_usage, across Tasks; reset to zero after compaction completes. */
|
|
1038
|
+
private sessionTurns;
|
|
1039
|
+
/** Whether the current context was produced by a compaction (`startNewContext`); this flag becomes meaningless once a new completed turn occurs. */
|
|
1040
|
+
private fromCompaction;
|
|
1041
|
+
/** Most recent token_usage's request.total, i.e. the current context usage figure. */
|
|
1042
|
+
private lastRequestTotal;
|
|
1043
|
+
/** Most recent token_usage's session cumulative counts, handed to the new LLM object when compaction swaps it in. */
|
|
1044
|
+
private lastSessionTokens;
|
|
1045
|
+
/** Summary produced by a Task-boundary compaction: used as the prefix of the next `run` input (merged with the next user Prompt). */
|
|
1046
|
+
private pendingSummary;
|
|
1047
|
+
/**
|
|
1048
|
+
* Set to true once compaction completes: Trace rotation is deferred until the next
|
|
1049
|
+
* message that needs writing (see `write`) — so that if no further messages follow the
|
|
1050
|
+
* compaction, we don't create an empty file containing only session_meta.
|
|
1051
|
+
*/
|
|
1052
|
+
private pendingTraceRotation;
|
|
1053
|
+
constructor(deps: ContextEngineDeps);
|
|
1054
|
+
/**
|
|
1055
|
+
* Runs a Task to completion, streaming out OmniMessage. `newMessages` is this call's
|
|
1056
|
+
* Prompt (only the newly added input, not the full history — history is maintained by the
|
|
1057
|
+
* stateful GenerativeModel); `opts.signal` is the abort signal, `opts.approve` is the
|
|
1058
|
+
* per-tool approval callback.
|
|
1059
|
+
* Docs: /docs/agent-loop § "The loop at a glance".
|
|
1060
|
+
*/
|
|
1061
|
+
run(newMessages: OmniMessage[], opts?: RunOptions): AsyncGenerator<OmniMessage>;
|
|
1062
|
+
/**
|
|
1063
|
+
* User-initiated compaction request (e.g. a CLI command): reuses the automatic compaction
|
|
1064
|
+
* flow without checking thresholds (reason=manual). Only callable at a Task boundary (between
|
|
1065
|
+
* runs); streams out paired compaction events. No-op when compaction is not configured.
|
|
1066
|
+
*
|
|
1067
|
+
* Carry-over left over from an interruption is cleaned up here too: summarize folds it into
|
|
1068
|
+
* the compaction request (structured tool outputs keep their pairing with the already
|
|
1069
|
+
* committed tool_call, otherwise the compaction request itself would be rejected by the
|
|
1070
|
+
* provider as an unanswered tool_use, see issue #33; flatten text is absorbed into the
|
|
1071
|
+
* summary); discard drops the structured outputs paired with the old context, keeping only the
|
|
1072
|
+
* self-contained flatten text.
|
|
1073
|
+
*/
|
|
1074
|
+
/**
|
|
1075
|
+
* Whether compaction is possible, and the **reason** when it isn't.
|
|
1076
|
+
*
|
|
1077
|
+
* `compact()` is a no-op and **yields no messages** in these cases; if the UI treats invoking
|
|
1078
|
+
* it as a successful start, it ends up waiting forever for a compaction banner that never
|
|
1079
|
+
* arrives — that's exactly how "/compact does nothing after an interruption" happens. Callers
|
|
1080
|
+
* (Web / CLI) should give feedback upfront based on this.
|
|
1081
|
+
*
|
|
1082
|
+
* - `unsupported`: compaction capability is not configured;
|
|
1083
|
+
* - `empty`: the current context hasn't completed a single turn (`sessionTurns` only
|
|
1084
|
+
* increments when `token_usage` arrives — a turn only counts once the request finishes
|
|
1085
|
+
* normally, so it's still 0 right after the first request is interrupted);
|
|
1086
|
+
* - `just_compacted`: no new conversation since the last compaction. Both cases have
|
|
1087
|
+
* `sessionTurns` === 0, but they mean two completely different things to the user and must
|
|
1088
|
+
* not be conflated.
|
|
1089
|
+
*/
|
|
1090
|
+
compactability(): CompactAvailability;
|
|
1091
|
+
compact(opts?: {
|
|
1092
|
+
signal?: AbortSignal;
|
|
1093
|
+
}): AsyncGenerator<OmniMessage>;
|
|
1094
|
+
/**
|
|
1095
|
+
* Linear backoff before a reconnect retry (base × retry number, numbering starts at 1);
|
|
1096
|
+
* returns false if the user interrupts during the backoff, so the caller can proceed to
|
|
1097
|
+
* interruption cleanup.
|
|
1098
|
+
*/
|
|
1099
|
+
private backoff;
|
|
1100
|
+
/**
|
|
1101
|
+
* Runs one LLM turn: consumes the LLM stream, approving each complete tool_call immediately;
|
|
1102
|
+
* "allow" runs it concurrently (without blocking further stream consumption/approval), "deny"
|
|
1103
|
+
* feeds back an aborted output. partial/complete tool_call_output is yielded in completion
|
|
1104
|
+
* order. Returns all of this turn's tool outputs (for the next turn) and whether it was
|
|
1105
|
+
* interrupted midway.
|
|
1106
|
+
* Docs: /docs/agent-loop § "Lifecycle of a turn".
|
|
1107
|
+
*/
|
|
1108
|
+
private runTurn;
|
|
1109
|
+
/**
|
|
1110
|
+
* Executes a single approved tool: streams its partial/complete tool_call_output (through the
|
|
1111
|
+
* queue), and collects the complete tool_call_output into toolOutputs.
|
|
1112
|
+
*
|
|
1113
|
+
* Environment is contracted to handle all errors internally: it guarantees exactly one
|
|
1114
|
+
* complete `tool_call_output` to close out and never throws. But since
|
|
1115
|
+
* EnvironmentInterface can be injected by consumers via a public API, if a contract-violating
|
|
1116
|
+
* exception escapes, this fire-and-forget promise would take down the process with an
|
|
1117
|
+
* unhandled rejection, and the missing output would leave the already-committed tool_use
|
|
1118
|
+
* unanswered (the next request gets rejected by the provider) — so a boundary safety net is
|
|
1119
|
+
* kept here, collapsing a contract-violating exception into a failed output. This guarantees
|
|
1120
|
+
* exactly one complete output per tool enters toolOutputs, keeping tool_use and tool_result
|
|
1121
|
+
* paired.
|
|
1122
|
+
*/
|
|
1123
|
+
private executeOne;
|
|
1124
|
+
/** Max turns reached: emits a failed notice (streaming fragments + complete text) for CLI/frontend rendering. */
|
|
1125
|
+
private emitMaxTurns;
|
|
1126
|
+
/**
|
|
1127
|
+
* Checks the compaction threshold: triggers once context usage (the most recent
|
|
1128
|
+
* token_usage's request.total) or the Session cumulative turn count **reaches** the threshold
|
|
1129
|
+
* (>=) — e.g. maxSessionTurns=1 compacts as soon as turn 1 completes, without waiting for the
|
|
1130
|
+
* next Task; when both are configured, either reaching its threshold triggers compaction.
|
|
1131
|
+
* Never triggers when compaction is not configured.
|
|
1132
|
+
* Docs: /docs/agent-loop § "Compaction".
|
|
1133
|
+
*/
|
|
1134
|
+
private compactionTrigger;
|
|
1135
|
+
/** Records context usage and Session cumulative counts from a token_usage event; returns whether the message is a token_usage. */
|
|
1136
|
+
private observeTokenUsage;
|
|
1137
|
+
/**
|
|
1138
|
+
* `discard` compaction: sends no compaction request, simply discards the old context —
|
|
1139
|
+
* swaps in a new LLM object and splits a new Trace file, with the next turn's input used
|
|
1140
|
+
* unchanged as the new object's first input. Only runs at a Task boundary (deferred by the
|
|
1141
|
+
* caller while mid-Task).
|
|
1142
|
+
*/
|
|
1143
|
+
private discardContext;
|
|
1144
|
+
/**
|
|
1145
|
+
* `summarize` compaction: appends the compaction Prompt to the **old** LLM object (first
|
|
1146
|
+
* folding in all of this turn's tool results when mid-Task, to keep tool_use/tool_result
|
|
1147
|
+
* pairing), then extracts the `<summary>` and wraps it as `<context_summary>` user text. The
|
|
1148
|
+
* compaction request's streamed output is not pushed to the Human output stream (it emits
|
|
1149
|
+
* paired compaction events, plus the compaction request's `token_usage` — positioned between
|
|
1150
|
+
* the two events, so the frontend can count compaction cost into its stats), but it is written
|
|
1151
|
+
* to the old Trace. timeout/malformed reconnect via the existing retry mechanism, collapsing
|
|
1152
|
+
* to failed once retries are exhausted; on failure/abort, the original context and Trace index
|
|
1153
|
+
* are kept — it does not fall back to discard.
|
|
1154
|
+
* Docs: /docs/agent-loop § "Compaction".
|
|
1155
|
+
*/
|
|
1156
|
+
private summarizeContext;
|
|
1157
|
+
/**
|
|
1158
|
+
* Issues one compaction request (an ordinary LLM Request): consumes the old LLM object's
|
|
1159
|
+
* streamed output but **does not push it to the Human output stream** (except `token_usage`
|
|
1160
|
+
* — captured and handed back via the return value for summarizeContext to yield); complete
|
|
1161
|
+
* messages and events are written to the old Trace; complete text segments are collected as
|
|
1162
|
+
* the compaction output. Token usage is counted into the Session cumulative totals (recorded
|
|
1163
|
+
* via observeTokenUsage, for the new object to carry forward).
|
|
1164
|
+
*/
|
|
1165
|
+
private runCompactionRequest;
|
|
1166
|
+
/**
|
|
1167
|
+
* Opens a new model context after successful compaction: swaps in a new LLM object (carrying
|
|
1168
|
+
* forward the Session cumulative token counts), resets the Session turn count and context
|
|
1169
|
+
* usage counter. Trace **does not** split files immediately — that's deferred until the next
|
|
1170
|
+
* message that needs writing, when it rotates and opens with a session_meta (see `write`),
|
|
1171
|
+
* avoiding an empty file if no further messages follow the compaction.
|
|
1172
|
+
*/
|
|
1173
|
+
private startNewContext;
|
|
1174
|
+
/** Yields and records a compaction start event (carrying reason/mode/current context usage/Session cumulative turns). */
|
|
1175
|
+
private emitCompactionBegin;
|
|
1176
|
+
/** Yields and records a compaction stop event (carrying the result status; non-completed means compaction was abandoned). */
|
|
1177
|
+
private emitCompactionEnd;
|
|
1178
|
+
/** Interruption: emits an abort event. Cleanup/resending is managed centrally by `run` via carry-over; the LLM history is never touched again. */
|
|
1179
|
+
private emitAbort;
|
|
1180
|
+
/**
|
|
1181
|
+
* Builds the interruption resend content (carry-over, interruption cleanup)
|
|
1182
|
+
* based on the LLM's terminal state. Used only for the **exit** cleanup of
|
|
1183
|
+
* aborted / failed (reconnect retry doesn't go through here — retry input is assembled by
|
|
1184
|
+
* withRetriedTurns, appending `<turn_retried>` with the failed attempt's output, distinct
|
|
1185
|
+
* from the user-interruption `<turn_aborted>`):
|
|
1186
|
+
* - Model output completed (case A, outcome=completed): AgentHub already committed an
|
|
1187
|
+
* assistant turn containing `tool_call`, so it can only be resent as a structured
|
|
1188
|
+
* `tool_call_output` to pair with it (cannot flatten, or the already-committed tool_call
|
|
1189
|
+
* would be left unanswered and rejected).
|
|
1190
|
+
* - Model output incomplete (case B): the `tool_call_output` in this turn's input (paired
|
|
1191
|
+
* with the previous completed turn) is kept as-is; the text input and this turn's
|
|
1192
|
+
* thinking/text/tool call/result are flattened into a single `<turn_aborted>` plain-text
|
|
1193
|
+
* user message.
|
|
1194
|
+
* Docs: /docs/agent-loop § "Interruption and carry-over".
|
|
1195
|
+
*/
|
|
1196
|
+
private buildCarryOver;
|
|
1197
|
+
/**
|
|
1198
|
+
* Case B: flattens this attempt's input and its produced content into carry-over. Structured
|
|
1199
|
+
* `tool_call_output` in the input (paired with the previous completed turn) is kept as-is;
|
|
1200
|
+
* everything else (text input, model thinking/text, this attempt's tool calls/results) is
|
|
1201
|
+
* transcribed into a single `<turn_aborted>` plain-text user message (includes all
|
|
1202
|
+
* completed and incomplete messages, including partial thinking/text). If the input text is
|
|
1203
|
+
* itself already a `<turn_aborted>` block (from a previous attempt or a previous run's
|
|
1204
|
+
* carry-over), its content is unwrapped and merged in, keeping a single-level structure.
|
|
1205
|
+
*
|
|
1206
|
+
* TODO(multimodal): only text input is currently kept — `image_url` / `inline_data` input is
|
|
1207
|
+
* lost during flatten (the `<turn_aborted>` structure has no corresponding transcription yet);
|
|
1208
|
+
* multimodal carry-over support to be added later.
|
|
1209
|
+
*/
|
|
1210
|
+
private flattenCarryOver;
|
|
1211
|
+
/** Transcribes the interrupted turn's input, model thinking/text, and tool calls/results into a single `<turn_aborted>` plain-text block. */
|
|
1212
|
+
private buildTurnAbortedText;
|
|
1213
|
+
/**
|
|
1214
|
+
* Assembles the reconnect retry input: the original input is kept as-is (structure and
|
|
1215
|
+
* multimodal content preserved), with a `<turn_retried>` text appended at the end carrying
|
|
1216
|
+
* each failed attempt's thinking/text and tool calls/results produced so far; if nothing has
|
|
1217
|
+
* been produced yet, it's just the original input. The synthetic message is sent to the model
|
|
1218
|
+
* only and not written to Trace (same rule as flatten carry-over).
|
|
1219
|
+
* Docs: /docs/agent-loop § "Automatic reconnect".
|
|
1220
|
+
*/
|
|
1221
|
+
private withRetriedTurns;
|
|
1222
|
+
/**
|
|
1223
|
+
* Trace writes are **best-effort**: observability should never interrupt the ReAct
|
|
1224
|
+
* loop, so write failures only warn rather than throw. The first write after compaction first
|
|
1225
|
+
* performs the deferred Trace rotation: splitting the file and opening it with session_meta.
|
|
1226
|
+
*/
|
|
1227
|
+
private write;
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1230
|
+
interface SessionTitleResult {
|
|
1231
|
+
/** The sanitized title; null when material is insufficient, the request fails, or the output is empty. */
|
|
1232
|
+
title: string | null;
|
|
1233
|
+
/** Token consumption for this request (accumulated token_usage.request); null if no request occurred or there's no usage. */
|
|
1234
|
+
usage: TokenCounts | null;
|
|
1235
|
+
}
|
|
1236
|
+
/**
|
|
1237
|
+
* Assembles the title-generation Prompt (exported for host/test assertion use). Uses English
|
|
1238
|
+
* instructions to avoid polluting the title's language, and requires the **title to be in the
|
|
1239
|
+
* same language as the conversation** (English conversation gets an English title, Chinese
|
|
1240
|
+
* conversation gets a Chinese title); when assistant material is empty, it relies on the user
|
|
1241
|
+
* request alone.
|
|
1242
|
+
*/
|
|
1243
|
+
declare function buildTitlePrompt(userExcerpt: string, assistantExcerpt: string): string;
|
|
1244
|
+
/** Sanitizes model output into a title: strips leading/trailing quotes/brackets and trailing punctuation (until stable), collapses whitespace, and truncates if too long; returns null for an empty result. */
|
|
1245
|
+
declare function sanitizeTitle(raw: string): string | null;
|
|
1246
|
+
/**
|
|
1247
|
+
* Drives a single title-generation request: collects model text and token_usage, and resolves
|
|
1248
|
+
* based on the outcome. Generation only requires user material (assistant material may be
|
|
1249
|
+
* empty — a pure tool-only turn can still get a title); no request is sent if user material is
|
|
1250
|
+
* empty; `title` is null if the request doesn't complete (any usage already produced is still
|
|
1251
|
+
* returned).
|
|
1252
|
+
*/
|
|
1253
|
+
declare function generateTitleWithLLM(llm: LLMInterface, args: {
|
|
1254
|
+
userText: string;
|
|
1255
|
+
assistantText: string;
|
|
1256
|
+
signal?: AbortSignal;
|
|
1257
|
+
}): Promise<SessionTitleResult>;
|
|
1258
|
+
|
|
1259
|
+
interface SessionConfig {
|
|
1260
|
+
/** Session metadata (session_id / provider / model_id / model_context_window / system_prompt / tools / thinking_level / agent_state / workspace). */
|
|
1261
|
+
meta: SessionMetaPayload;
|
|
1262
|
+
llm: LLMInterface;
|
|
1263
|
+
environment: EnvironmentInterface;
|
|
1264
|
+
trace?: TraceSink;
|
|
1265
|
+
maxTurns?: number;
|
|
1266
|
+
/** Creates a new LLM object after compaction (carries over the Session's accumulated Token count); context compaction is unavailable if not provided. */
|
|
1267
|
+
createLLM?: (sessionTokens: TokenCounts) => LLMInterface;
|
|
1268
|
+
/**
|
|
1269
|
+
* Factory for the bare LLM used by out-of-band, one-off requests (same Model/credential as
|
|
1270
|
+
* the session; no tools, no system prompt, thinking off): used for meta-requests such as
|
|
1271
|
+
* `generateTitle`; if not provided, `generateTitle` returns null.
|
|
1272
|
+
*/
|
|
1273
|
+
createBareLLM?: () => LLMInterface;
|
|
1274
|
+
/** Context compaction settings (defaults are filled in by the composition layer); only takes effect when provided together with `createLLM`. */
|
|
1275
|
+
compaction?: CompactionSettings;
|
|
1276
|
+
/** Session resume: `session_meta` is already in the original Trace file, so it isn't written again on the first run (avoids duplication). */
|
|
1277
|
+
metaAlreadyWritten?: boolean;
|
|
1278
|
+
/** Session resume: the engine's initial state derived from Trace replay (carry-over / accumulated stats, etc.). */
|
|
1279
|
+
initialEngineState?: EngineInitialState;
|
|
1280
|
+
/** Session resume: the full historical messages of the current context (for rendering, including interrupted turns and their markers), for frontend display. */
|
|
1281
|
+
resumedHistory?: OmniMessage[];
|
|
1282
|
+
/**
|
|
1283
|
+
* Set when the session's model doesn't support images (the composition layer decides this via
|
|
1284
|
+
* ModelEntry.vision): images in `run` input are saved to this directory (the session's
|
|
1285
|
+
* scratchpad), and the path is appended to the user text instead — the model views the image
|
|
1286
|
+
* via describe_image, and images never enter the session history directly (some providers
|
|
1287
|
+
* return a 400 outright on image input).
|
|
1288
|
+
*/
|
|
1289
|
+
inputImagesDir?: string;
|
|
1290
|
+
}
|
|
1291
|
+
declare class Session {
|
|
1292
|
+
readonly sessionId: string;
|
|
1293
|
+
/** The session model's provider group (paired with `modelId` to form the model reference). */
|
|
1294
|
+
readonly provider: string;
|
|
1295
|
+
/** The session model's upstream model_id (the request id sent to AgentHub). */
|
|
1296
|
+
readonly modelId: string;
|
|
1297
|
+
readonly workspaceDir: string;
|
|
1298
|
+
/** Session resume: the full historical messages of the current context (for rendering); undefined for a non-resumed Session. */
|
|
1299
|
+
readonly resumedHistory?: OmniMessage[];
|
|
1300
|
+
private readonly engine;
|
|
1301
|
+
private readonly environment;
|
|
1302
|
+
private readonly trace?;
|
|
1303
|
+
private readonly meta;
|
|
1304
|
+
private readonly createBareLLM?;
|
|
1305
|
+
private readonly inputImagesDir?;
|
|
1306
|
+
private metaWritten;
|
|
1307
|
+
/** Title material (used by `generateTitle` as the default): the user input and model body text of the first Task that contains user text. */
|
|
1308
|
+
private titleUserText;
|
|
1309
|
+
private titleAssistantText;
|
|
1310
|
+
/** Material-frozen flag: becomes true once the first Task containing user text finishes; subsequent runs stop accumulating. */
|
|
1311
|
+
private titleMaterialFrozen;
|
|
1312
|
+
constructor(config: SessionConfig);
|
|
1313
|
+
/**
|
|
1314
|
+
* Runs a Task to completion and streams out OmniMessage. `newMessages` is this call's Prompt
|
|
1315
|
+
* (only the newly added input); `opts` carries the abort signal `signal` and the per-call
|
|
1316
|
+
* approval callback `approve` (the engine calls it once per tool_call within a turn).
|
|
1317
|
+
* On the first run, `session_meta` is written to the Trace first.
|
|
1318
|
+
*
|
|
1319
|
+
* A single `run` automatically drives the whole ReAct loop: consuming the LLM stream,
|
|
1320
|
+
* approving and executing tools one at a time, feeding results back for the next turn,
|
|
1321
|
+
* until a turn no longer produces a tool_call (Task ends) or it's aborted.
|
|
1322
|
+
* Docs: /docs/agent-loop § "The loop at a glance".
|
|
1323
|
+
*/
|
|
1324
|
+
run(newMessages: OmniMessage[], opts?: RunOptions): AsyncGenerator<OmniMessage>;
|
|
1325
|
+
/**
|
|
1326
|
+
* User-initiated request to compact context (e.g. a CLI command): reuses the automatic
|
|
1327
|
+
* compaction flow but skips the threshold check (reason=manual). Only callable at Task
|
|
1328
|
+
* boundaries (between runs); streams out paired `compaction` events. The summarize digest
|
|
1329
|
+
* becomes the prefix of the next `run`'s input (merged with the next user Prompt). A no-op
|
|
1330
|
+
* if compaction isn't configured.
|
|
1331
|
+
* Docs: /docs/agent-loop § "Compaction".
|
|
1332
|
+
*/
|
|
1333
|
+
compact(opts?: {
|
|
1334
|
+
signal?: AbortSignal;
|
|
1335
|
+
}): AsyncGenerator<OmniMessage>;
|
|
1336
|
+
/**
|
|
1337
|
+
* Whether compaction is possible, and why not if not (see ContextEngine.compactability).
|
|
1338
|
+
* When the result isn't `ok`, `compact()` is a no-op and yields no messages — callers should
|
|
1339
|
+
* give feedback based on this rather than triggering a silent, fruitless compaction.
|
|
1340
|
+
*/
|
|
1341
|
+
compactability(): CompactAvailability;
|
|
1342
|
+
/** Writes `session_meta` to the Trace before the first run/compaction; best-effort — failure doesn't interrupt the run. */
|
|
1343
|
+
private ensureMetaWritten;
|
|
1344
|
+
/**
|
|
1345
|
+
* Out-of-band, one-off request that generates a short title from the first-turn conversation
|
|
1346
|
+
* text: sends one request using the bare LLM for the session's Model (no
|
|
1347
|
+
* tools, no system prompt, thinking off), **without writing history or Trace**. Material
|
|
1348
|
+
* defaults to the first Task text self-captured by the Session (user input and model body
|
|
1349
|
+
* text collected during run; thinking and tool calls don't count), so callers don't need to
|
|
1350
|
+
* supply it; `material` can override this (e.g. when a host generates a title for a
|
|
1351
|
+
* sub-session — the material is that sub-session's own conversation). `title` is null if the
|
|
1352
|
+
* material is empty, the request fails, or the composition layer didn't supply a bare LLM
|
|
1353
|
+
* factory. Token consumption is returned via `usage` for the host to account for.
|
|
1354
|
+
* Docs: /docs/agent-loop § "Side channels".
|
|
1355
|
+
*/
|
|
1356
|
+
generateTitle(args?: {
|
|
1357
|
+
/** Material override; defaults to the Session's self-captured material. */
|
|
1358
|
+
material?: {
|
|
1359
|
+
userText: string;
|
|
1360
|
+
assistantText: string;
|
|
1361
|
+
};
|
|
1362
|
+
signal?: AbortSignal;
|
|
1363
|
+
}): Promise<SessionTitleResult>;
|
|
1364
|
+
/** Queries a tool's permission level (for the frontend to determine permission mode); returns undefined for unknown tools. */
|
|
1365
|
+
toolPermission(name: string): ToolPermission | undefined;
|
|
1366
|
+
/** This Session's session_meta message (used e.g. by host tools to forward nested-session metadata to a parent session). */
|
|
1367
|
+
get metaMessage(): OmniMessage;
|
|
1368
|
+
/**
|
|
1369
|
+
* Releases runtime resources held by the Session: kills long-running command sessions
|
|
1370
|
+
* managed by the Environment. The host calls this when the Session ends (CLI exit, Web
|
|
1371
|
+
* session close) to avoid leaking background processes into the host process's lifetime.
|
|
1372
|
+
* Optional, idempotent.
|
|
1373
|
+
*/
|
|
1374
|
+
dispose(): void;
|
|
1375
|
+
}
|
|
1376
|
+
|
|
1377
|
+
interface CreateAgentOptions {
|
|
1378
|
+
agentId?: string;
|
|
1379
|
+
projectId?: string;
|
|
1380
|
+
/** Local data root directory; defaults to `resolveRoot()` (PENGUIN_HOME or ~/.penguin/data). */
|
|
1381
|
+
root?: string;
|
|
1382
|
+
}
|
|
1383
|
+
interface CreateSessionOptions {
|
|
1384
|
+
/** Workspace for this run; if unspecified, a temporary Workspace is created under the Agent directory. */
|
|
1385
|
+
workspaceDir?: string;
|
|
1386
|
+
/** Model used for this Session (upstream model_id); if unspecified, uses the Project's default Model. */
|
|
1387
|
+
modelId?: string;
|
|
1388
|
+
/**
|
|
1389
|
+
* Provider grouping for `modelId` (a paired reference); if omitted, resolved via
|
|
1390
|
+
* `resolveModelRef` semantics — `model_id` only resolves if it is a globally unique
|
|
1391
|
+
* exact match in the config; zero or multiple matches produce a clear error.
|
|
1392
|
+
*/
|
|
1393
|
+
provider?: string;
|
|
1394
|
+
/** Explicit credentials; if unspecified, falls back to credentials in the Project config, then to AgentHub reading environment variables. */
|
|
1395
|
+
apiKey?: string;
|
|
1396
|
+
baseUrl?: string;
|
|
1397
|
+
/** Internal use: this Session's depth in the subagent spawn chain (0 at the top level), used to cap spawn depth. */
|
|
1398
|
+
subagentDepth?: number;
|
|
1399
|
+
}
|
|
1400
|
+
interface ResumeSessionOptions {
|
|
1401
|
+
/** Id of the Session to resume. */
|
|
1402
|
+
sessionId: string;
|
|
1403
|
+
/** Explicit credentials; if unspecified, falls back to credentials in the Project config, then to AgentHub reading environment variables. */
|
|
1404
|
+
apiKey?: string;
|
|
1405
|
+
baseUrl?: string;
|
|
1406
|
+
}
|
|
1407
|
+
/** Create or load an Agent. */
|
|
1408
|
+
declare function createAgent(opts?: CreateAgentOptions): Promise<Agent>;
|
|
1409
|
+
declare class Agent {
|
|
1410
|
+
readonly state: AgentState;
|
|
1411
|
+
readonly projectConfig: ProjectConfig;
|
|
1412
|
+
constructor(state: AgentState, projectConfig: ProjectConfig);
|
|
1413
|
+
/**
|
|
1414
|
+
* Create a Session in the specified (or a temporary) Workspace.
|
|
1415
|
+
* Docs: /docs/sessions-and-traces § "Run model".
|
|
1416
|
+
*/
|
|
1417
|
+
createSession(opts?: CreateSessionOptions): Promise<Session>;
|
|
1418
|
+
/**
|
|
1419
|
+
* Resume an existing Session and continue the conversation.
|
|
1420
|
+
*
|
|
1421
|
+
* The resume source is the Session's **latest-index** Trace file: runtime config is
|
|
1422
|
+
* read from its `session_meta` (Model, the original system prompt text, and the
|
|
1423
|
+
* Workspace all carry over from the original Session and cannot be changed), while
|
|
1424
|
+
* tools and Environment are reassembled from the current Agent State. The replayed,
|
|
1425
|
+
* already-committed history is injected once via AgentHub's setHistory (used only on
|
|
1426
|
+
* resume); any leftover input is rebuilt as carry-over (paired fallback placeholders
|
|
1427
|
+
* are synthesized in memory only, never written to the Trace). Messages after resume
|
|
1428
|
+
* continue in the original Trace file (the file follows the context, not the date),
|
|
1429
|
+
* and Token / turn-count stats carry over from their original values.
|
|
1430
|
+
* Docs: /docs/sessions-and-traces § "Session recovery".
|
|
1431
|
+
*/
|
|
1432
|
+
resumeSession(opts: ResumeSessionOptions): Promise<Session>;
|
|
1433
|
+
/** Id of the most recent Session under the current Agent (determined by the timestamp in session_id); returns null if there is no Session. */
|
|
1434
|
+
latestSessionId(): Promise<string | null>;
|
|
1435
|
+
/**
|
|
1436
|
+
* Assemble a Session's runtime components (shared by createSession and
|
|
1437
|
+
* resumeSession): the child-Agent runner, Environment and tools, the LLM object
|
|
1438
|
+
* and its post-compaction rebuild factory, and the compaction config.
|
|
1439
|
+
*/
|
|
1440
|
+
private buildRuntime;
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
/**
|
|
1444
|
+
* @prismshadow/penguin-core — public entry point for the PenguinHarness core SDK.
|
|
1445
|
+
*
|
|
1446
|
+
* Exports the OmniMessage protocol, the three interface contracts (Human/LLM/Environment),
|
|
1447
|
+
* and the runtime entry points for Agent / Session / context_engine along with their
|
|
1448
|
+
* submodules (state / llm / environment / trace).
|
|
1449
|
+
*
|
|
1450
|
+
* Typical usage:
|
|
1451
|
+
*
|
|
1452
|
+
* ```ts
|
|
1453
|
+
* const agent = await createAgent({ agentId: "default_agent" });
|
|
1454
|
+
* const session = await agent.createSession({ workspaceDir, modelId });
|
|
1455
|
+
* for await (const output of session.run([userText("...")])) { ... }
|
|
1456
|
+
* ```
|
|
1457
|
+
*/
|
|
1458
|
+
|
|
1459
|
+
/** SDK version number. */
|
|
1460
|
+
declare const VERSION = "0.0.1";
|
|
1461
|
+
|
|
1462
|
+
export { AGENTS_MD_PLACEHOLDER, AGENT_ID_PLACEHOLDER, Agent, type AgentPreset, type AgentState, ApproveFn, BUILTIN_AGENT_IDS, BUILTIN_TOOL_FACTORIES, type BuiltinTool, type BuiltinToolFactory, CWD_PLACEHOLDER, type CompactAvailability, type CompactionConfig, CompactionMode, type CompactionSettings, CompleteModelMessage, ContextEngine, type ContextEngineDeps, type CreateAgentOptions, type CreateSessionOptions, DATE_PLACEHOLDER, DEFAULT_AGENT_ID, DEFAULT_COMPACTION_PROMPT, DEFAULT_PROJECT_ID, EXAMPLE_BENCHMARK_ID, EXEC_COMMAND_NAME, type EngineInitialState, Environment, EnvironmentConfig, EnvironmentInterface, EnvironmentServices, EventTranslator, GenerativeModel, GenerativeModelConfig, GenerativeModelParameters, INPUT_COMMAND_NAME, INPUT_SUBAGENT_NAME, type IdKind, type InstalledSkill, LLMInterface, LLMOutcome, type LocatedTraceFile, MCPServerConfig, OS_VERSION_PLACEHOLDER, OmniMessage, PLATFORM_PLACEHOLDER, PROJECT_DIR_PLACEHOLDER, ProjectConfig, type ResumeResult, type ResumeSessionOptions, type RunOptions, SESSION_ID_PLACEHOLDER, SKILL_METADATA_PLACEHOLDER, SUBAGENT_NAME, Session, type SessionConfig, type SessionEnvironmentValues, SessionMetaMessage, SessionMetaPayload, type SessionTitleResult, StopReason, type SystemConfig, ThinkingLevelName, TokenCounts, ToolCallIdAllocator, ToolConfig, ToolDefinition, ToolDefinitionConfig, type ToolExecutionContext, ToolExecutionRequest, ToolPermission, type TraceSink, VAULT_KEYS_PLACEHOLDER, VAULT_VALUE_MAX_LENGTH, VERSION, Writer, type WriterOptions, agentDir, agentStateDir, agentStateVersion, agentVaultPath, agentsDir, agentsMdPath, assembleSystemPrompt, assertValidId, assertValidVaultKey, assertValidVaultValue, benchmarksDir, buildExampleScoreboard, buildTitlePrompt, buildToolConfig, buildUniConfig, builtinProjectAgentPresets, createAgent, createExecCommandTool, createInputCommandTool, createInputSubagentTool, createSubagentTool, defaultAgentsMd, defaultSystemConfig, findLatestTraceFile, generateTitleWithLLM, groupHistoryToUniMessages, installSkill, isIncompleteStreamError, isMalformedJsonParseError, isRetryableError, isValidId, isValidVaultKey, latestSessionId, listInstalledSkills, loadAgentVault, loadOrInitAgentState, mapThinkingLevel, memoryDir, mergeOmniToUniMessage, parseTraceLines, projectConfigPath, projectDir, provisionExampleBenchmark, provisionProjectAgents, readTrace, readTraceTolerant, removeSkill, removeVaultEntry, resolveRoot, resumeTrace, sanitizeTitle, saveAgentVault, scheduleDir, scratchpadDir, selectBuiltinToolsForModel, setVaultEntry, skillMetadataSection, skillsDir, snapshotsDir, systemConfigPath, toolDefinitionsToSchemas, toolsDir, tracesDir, translateEvents, usageToTokenCounts, workspacesDir };
|