@clinebot/core 0.0.36 → 0.0.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ClineCore.d.ts +312 -3
- package/dist/ClineCore.d.ts.map +1 -1
- package/dist/account/cline-account-service.d.ts.map +1 -1
- package/dist/cron/cron-event-ingress.d.ts +38 -0
- package/dist/cron/cron-event-ingress.d.ts.map +1 -0
- package/dist/cron/cron-materializer.d.ts +36 -0
- package/dist/cron/cron-materializer.d.ts.map +1 -0
- package/dist/cron/cron-reconciler.d.ts +62 -0
- package/dist/cron/cron-reconciler.d.ts.map +1 -0
- package/dist/cron/cron-report-writer.d.ts +41 -0
- package/dist/cron/cron-report-writer.d.ts.map +1 -0
- package/dist/cron/cron-runner.d.ts +43 -0
- package/dist/cron/cron-runner.d.ts.map +1 -0
- package/dist/cron/cron-schema.d.ts +3 -0
- package/dist/cron/cron-schema.d.ts.map +1 -0
- package/dist/cron/cron-service.d.ts +57 -0
- package/dist/cron/cron-service.d.ts.map +1 -0
- package/dist/cron/cron-spec-parser.d.ts +27 -0
- package/dist/cron/cron-spec-parser.d.ts.map +1 -0
- package/dist/cron/cron-watcher.d.ts +23 -0
- package/dist/cron/cron-watcher.d.ts.map +1 -0
- package/dist/cron/scheduler.d.ts +3 -1
- package/dist/cron/scheduler.d.ts.map +1 -1
- package/dist/cron/sqlite-cron-store.d.ts +230 -0
- package/dist/cron/sqlite-cron-store.d.ts.map +1 -0
- package/dist/extensions/plugin/plugin-config-loader.d.ts +7 -1
- package/dist/extensions/plugin/plugin-config-loader.d.ts.map +1 -1
- package/dist/extensions/plugin/plugin-loader.d.ts +10 -6
- package/dist/extensions/plugin/plugin-loader.d.ts.map +1 -1
- package/dist/extensions/plugin/plugin-sandbox.d.ts +7 -1
- package/dist/extensions/plugin/plugin-sandbox.d.ts.map +1 -1
- package/dist/extensions/plugin-sandbox-bootstrap.js +236 -275
- package/dist/extensions/tools/constants.d.ts +1 -0
- package/dist/extensions/tools/constants.d.ts.map +1 -1
- package/dist/extensions/tools/definitions.d.ts +2 -3
- package/dist/extensions/tools/definitions.d.ts.map +1 -1
- package/dist/extensions/tools/executors/editor.d.ts.map +1 -1
- package/dist/extensions/tools/helpers.d.ts +1 -0
- package/dist/extensions/tools/helpers.d.ts.map +1 -1
- package/dist/extensions/tools/index.d.ts +1 -2
- package/dist/extensions/tools/index.d.ts.map +1 -1
- package/dist/extensions/tools/presets.d.ts +1 -1
- package/dist/extensions/tools/schemas.d.ts +25 -3
- package/dist/extensions/tools/schemas.d.ts.map +1 -1
- package/dist/extensions/tools/team/delegated-agent.d.ts +2 -2
- package/dist/extensions/tools/team/delegated-agent.d.ts.map +1 -1
- package/dist/extensions/tools/team/multi-agent.d.ts +7 -3
- package/dist/extensions/tools/team/multi-agent.d.ts.map +1 -1
- package/dist/extensions/tools/team/team-tools.d.ts.map +1 -1
- package/dist/extensions/tools/types.d.ts +0 -5
- package/dist/extensions/tools/types.d.ts.map +1 -1
- package/dist/hooks/hook-bridge.d.ts +118 -0
- package/dist/hooks/hook-bridge.d.ts.map +1 -0
- package/dist/hooks/hook-file-hooks.d.ts +2 -1
- package/dist/hooks/hook-file-hooks.d.ts.map +1 -1
- package/dist/hooks/hook-registry.d.ts +16 -0
- package/dist/hooks/hook-registry.d.ts.map +1 -0
- package/dist/hub/browser-websocket.d.ts.map +1 -1
- package/dist/hub/client.d.ts +7 -1
- package/dist/hub/client.d.ts.map +1 -1
- package/dist/hub/daemon-entry.js +721 -461
- package/dist/hub/daemon.d.ts.map +1 -1
- package/dist/hub/defaults.d.ts +8 -4
- package/dist/hub/defaults.d.ts.map +1 -1
- package/dist/hub/index.js +665 -415
- package/dist/hub/runtime-handlers.d.ts.map +1 -1
- package/dist/hub/server.d.ts +18 -0
- package/dist/hub/server.d.ts.map +1 -1
- package/dist/hub/session-client.d.ts +3 -0
- package/dist/hub/session-client.d.ts.map +1 -1
- package/dist/hub/start-shared-server.d.ts.map +1 -1
- package/dist/hub/ui-client.d.ts +1 -0
- package/dist/hub/ui-client.d.ts.map +1 -1
- package/dist/index.d.ts +9 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +756 -467
- package/dist/llms/cline-recommended-models.d.ts +20 -0
- package/dist/llms/cline-recommended-models.d.ts.map +1 -0
- package/dist/llms/handler-factory.d.ts +16 -0
- package/dist/llms/handler-factory.d.ts.map +1 -0
- package/dist/llms/provider-defaults.d.ts.map +1 -1
- package/dist/llms/provider-settings.d.ts +45 -2
- package/dist/llms/provider-settings.d.ts.map +1 -1
- package/dist/llms/runtime-registry.d.ts.map +1 -1
- package/dist/runtime/agent-config-adapter.d.ts +148 -0
- package/dist/runtime/agent-config-adapter.d.ts.map +1 -0
- package/dist/runtime/agent-runtime-config-builder.d.ts +96 -0
- package/dist/runtime/agent-runtime-config-builder.d.ts.map +1 -0
- package/dist/runtime/history.d.ts +6 -0
- package/dist/runtime/history.d.ts.map +1 -1
- package/dist/runtime/host.d.ts.map +1 -1
- package/dist/runtime/loop-detection.d.ts +59 -0
- package/dist/runtime/loop-detection.d.ts.map +1 -0
- package/dist/runtime/mistake-tracker.d.ts +69 -0
- package/dist/runtime/mistake-tracker.d.ts.map +1 -0
- package/dist/runtime/runtime-builder.d.ts.map +1 -1
- package/dist/runtime/runtime-event-adapter.d.ts +102 -0
- package/dist/runtime/runtime-event-adapter.d.ts.map +1 -0
- package/dist/runtime/runtime-host.d.ts +28 -3
- package/dist/runtime/runtime-host.d.ts.map +1 -1
- package/dist/runtime/session-runtime-orchestrator.d.ts +261 -0
- package/dist/runtime/session-runtime-orchestrator.d.ts.map +1 -0
- package/dist/runtime/session-runtime.d.ts +16 -3
- package/dist/runtime/session-runtime.d.ts.map +1 -1
- package/dist/runtime/user-input-builder.d.ts +24 -0
- package/dist/runtime/user-input-builder.d.ts.map +1 -0
- package/dist/services/index.js +28 -0
- package/dist/services/local-runtime-bootstrap.d.ts.map +1 -1
- package/dist/services/plugin-tools.d.ts.map +1 -1
- package/dist/services/providers/local-provider-registry.d.ts +197 -21
- package/dist/services/providers/local-provider-registry.d.ts.map +1 -1
- package/dist/services/providers/local-provider-service.d.ts +3 -1
- package/dist/services/providers/local-provider-service.d.ts.map +1 -1
- package/dist/services/session-data.d.ts.map +1 -1
- package/dist/services/session-telemetry.d.ts +7 -2
- package/dist/services/session-telemetry.d.ts.map +1 -1
- package/dist/services/storage/file-team-store.d.ts.map +1 -1
- package/dist/services/storage/provider-settings-legacy-migration.d.ts.map +1 -1
- package/dist/services/storage/provider-settings-manager.d.ts +1 -0
- package/dist/services/storage/provider-settings-manager.d.ts.map +1 -1
- package/dist/services/storage/sqlite-team-store.d.ts.map +1 -1
- package/dist/session/conversation-store.d.ts +30 -0
- package/dist/session/conversation-store.d.ts.map +1 -0
- package/dist/session/message-builder.d.ts +65 -0
- package/dist/session/message-builder.d.ts.map +1 -0
- package/dist/session/session-manifest.d.ts +1 -1
- package/dist/transports/hub.d.ts +14 -3
- package/dist/transports/hub.d.ts.map +1 -1
- package/dist/transports/local.d.ts +14 -4
- package/dist/transports/local.d.ts.map +1 -1
- package/dist/transports/remote.d.ts.map +1 -1
- package/dist/types/chat-schema.d.ts +5 -5
- package/dist/types/config.d.ts +9 -0
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/events.d.ts +7 -6
- package/dist/types/events.d.ts.map +1 -1
- package/dist/types/provider-settings.d.ts +2 -2
- package/dist/types/provider-settings.d.ts.map +1 -1
- package/dist/types/session.d.ts +5 -2
- package/dist/types/session.d.ts.map +1 -1
- package/dist/types.d.ts +4 -4
- package/dist/types.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/ClineCore.ts +691 -6
- package/src/account/cline-account-service.ts +44 -6
- package/src/cron/cron-event-ingress.ts +357 -0
- package/src/cron/cron-materializer.ts +97 -0
- package/src/cron/cron-reconciler.ts +241 -0
- package/src/cron/cron-report-writer.ts +153 -0
- package/src/cron/cron-runner.ts +495 -0
- package/src/cron/cron-schema.ts +127 -0
- package/src/cron/cron-service.ts +163 -0
- package/src/cron/cron-spec-parser.ts +489 -0
- package/src/cron/cron-watcher.ts +102 -0
- package/src/cron/index.ts +10 -0
- package/src/cron/scheduler.ts +141 -6
- package/src/cron/sqlite-cron-store.ts +1286 -0
- package/src/extensions/plugin/plugin-config-loader.ts +21 -1
- package/src/extensions/plugin/plugin-loader.ts +25 -9
- package/src/extensions/plugin/plugin-sandbox-bootstrap.ts +151 -1
- package/src/extensions/plugin/plugin-sandbox.ts +131 -7
- package/src/extensions/tools/constants.ts +2 -0
- package/src/extensions/tools/definitions.ts +31 -22
- package/src/extensions/tools/executors/editor.ts +4 -3
- package/src/extensions/tools/helpers.ts +24 -0
- package/src/extensions/tools/index.ts +1 -2
- package/src/extensions/tools/presets.ts +1 -1
- package/src/extensions/tools/schemas.ts +13 -18
- package/src/extensions/tools/team/delegated-agent.ts +8 -3
- package/src/extensions/tools/team/multi-agent.ts +135 -19
- package/src/extensions/tools/team/team-tools.ts +151 -91
- package/src/extensions/tools/types.ts +0 -6
- package/src/hooks/hook-bridge.ts +489 -0
- package/src/hooks/hook-file-hooks.ts +58 -3
- package/src/hooks/hook-registry.ts +257 -0
- package/src/hub/browser-websocket.ts +26 -4
- package/src/hub/client.ts +72 -13
- package/src/hub/daemon-entry.ts +35 -0
- package/src/hub/daemon.ts +117 -14
- package/src/hub/defaults.ts +39 -12
- package/src/hub/runtime-handlers.ts +4 -3
- package/src/hub/server.ts +506 -77
- package/src/hub/session-client.ts +43 -1
- package/src/hub/start-shared-server.ts +3 -0
- package/src/hub/ui-client.ts +4 -0
- package/src/index.ts +46 -1
- package/src/llms/cline-recommended-models.ts +167 -0
- package/src/llms/handler-factory.ts +56 -0
- package/src/llms/provider-defaults.ts +17 -1
- package/src/llms/provider-settings.ts +48 -1
- package/src/llms/runtime-registry.ts +1 -0
- package/src/runtime/agent-config-adapter.ts +636 -0
- package/src/runtime/agent-runtime-config-builder.ts +205 -0
- package/src/runtime/error-feedback.ts +142 -0
- package/src/runtime/history.ts +137 -0
- package/src/runtime/host.ts +22 -0
- package/src/runtime/loop-detection.ts +162 -0
- package/src/runtime/mistake-tracker.ts +221 -0
- package/src/runtime/runtime-builder.ts +61 -5
- package/src/runtime/runtime-event-adapter.ts +412 -0
- package/src/runtime/runtime-host.ts +45 -1
- package/src/runtime/session-runtime-orchestrator.ts +1253 -0
- package/src/runtime/session-runtime.ts +16 -2
- package/src/runtime/user-input-builder.ts +167 -0
- package/src/services/local-runtime-bootstrap.ts +128 -22
- package/src/services/plugin-tools.ts +1 -0
- package/src/services/providers/local-provider-registry.ts +273 -57
- package/src/services/providers/local-provider-service.ts +67 -7
- package/src/services/session-data.ts +16 -14
- package/src/services/session-telemetry.ts +6 -15
- package/src/services/storage/file-team-store.ts +1 -5
- package/src/services/storage/provider-settings-legacy-migration.ts +8 -47
- package/src/services/storage/provider-settings-manager.ts +16 -1
- package/src/services/storage/sqlite-team-store.ts +1 -5
- package/src/session/conversation-store.ts +77 -0
- package/src/session/message-builder.ts +941 -0
- package/src/transports/hub.ts +458 -33
- package/src/transports/local.ts +296 -65
- package/src/transports/remote.ts +1 -0
- package/src/types/config.ts +9 -0
- package/src/types/events.ts +8 -6
- package/src/types/index.ts +3 -0
- package/src/types/provider-settings.ts +8 -1
- package/src/types/session.ts +5 -2
- package/src/types.ts +15 -1
- package/dist/cron/index.d.ts +0 -6
- package/dist/cron/index.d.ts.map +0 -1
- package/dist/services/telemetry/index.js +0 -28
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build an `AgentRuntimeConfig` from an `AgentConfig` plus session-owned
|
|
3
|
+
* supporting objects (model handler, tools, hooks, plugins, telemetry).
|
|
4
|
+
*
|
|
5
|
+
* @see PLAN.md §3.1 — new file introduced alongside the core runtime port.
|
|
6
|
+
* @see PLAN.md §3.2.1 — field-by-field mapping.
|
|
7
|
+
*
|
|
8
|
+
* Implemented in Step 8c. The function is intentionally **pure** — it
|
|
9
|
+
* does not create handlers or tools itself; it receives them already
|
|
10
|
+
* adapted (via `agent-config-adapter.ts`) from the caller
|
|
11
|
+
* (`SessionRuntime`) and wires them into an `AgentRuntimeConfig`.
|
|
12
|
+
*
|
|
13
|
+
* Fields that do **not** round-trip into `AgentRuntimeConfig`
|
|
14
|
+
* (e.g. `execution.maxConsecutiveMistakes`,
|
|
15
|
+
* `execution.loopDetection`, `hookPolicies`) are
|
|
16
|
+
* consumed by `SessionRuntime` / `MistakeTracker` /
|
|
17
|
+
* `LoopDetectionTracker` — not passed through here. See §3.2.1's
|
|
18
|
+
* "Fields with no corresponding AgentRuntimeConfig slot" note.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import type {
|
|
22
|
+
AgentConfig,
|
|
23
|
+
AgentMessage,
|
|
24
|
+
AgentModel,
|
|
25
|
+
AgentRuntimeConfig,
|
|
26
|
+
AgentRuntimePlugin,
|
|
27
|
+
AgentTelemetry,
|
|
28
|
+
AgentTool,
|
|
29
|
+
BasicLogger,
|
|
30
|
+
} from "@clinebot/shared";
|
|
31
|
+
import type { HookBridge } from "../hooks/hook-bridge";
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Inputs required to assemble an `AgentRuntimeConfig`. Distinct from
|
|
35
|
+
* `AgentConfig` because some of these (the model adapter, the hook
|
|
36
|
+
* bridge's runtime-hooks bag, a resolved plugin list) can only be
|
|
37
|
+
* produced inside `SessionRuntime`.
|
|
38
|
+
*/
|
|
39
|
+
export interface CreateAgentRuntimeConfigInput {
|
|
40
|
+
readonly agentConfig: AgentConfig;
|
|
41
|
+
/**
|
|
42
|
+
* Core/hub runtime session identifier used for host lifecycle operations,
|
|
43
|
+
* event routing, persistence, and approval delivery.
|
|
44
|
+
*/
|
|
45
|
+
readonly sessionId?: string;
|
|
46
|
+
readonly agentId: string;
|
|
47
|
+
/**
|
|
48
|
+
* Agent conversation/transcript identifier used by tools, hooks, telemetry,
|
|
49
|
+
* and model history correlation.
|
|
50
|
+
*/
|
|
51
|
+
readonly conversationId?: string;
|
|
52
|
+
readonly parentAgentId?: string;
|
|
53
|
+
/** The role label for teammates (`AgentConfig.role` in sub-agent configs). */
|
|
54
|
+
readonly agentRole?: string;
|
|
55
|
+
/** Pre-built model adapter (produced by `apiHandlerToAgentModel`). */
|
|
56
|
+
readonly model: AgentModel;
|
|
57
|
+
readonly logger?: BasicLogger;
|
|
58
|
+
readonly telemetry?: AgentTelemetry;
|
|
59
|
+
/** Pre-built tool array (builtins + plugin-contributed + session extras). */
|
|
60
|
+
readonly tools?: readonly AgentTool<unknown, unknown>[];
|
|
61
|
+
/** Pre-resolved plugin list from the plugin loader. */
|
|
62
|
+
readonly plugins?: readonly AgentRuntimePlugin[];
|
|
63
|
+
/**
|
|
64
|
+
* Optional hook bridge. When provided, `AgentRuntimeConfig.hooks`
|
|
65
|
+
* is populated from `hookBridge.toRuntimeHooks()`. Omit for
|
|
66
|
+
* runtimes that do not need hook dispatch (e.g. unit tests).
|
|
67
|
+
*/
|
|
68
|
+
readonly hookBridge?: HookBridge;
|
|
69
|
+
/** Seed messages (usually `session.conversation.getMessages()`). */
|
|
70
|
+
readonly initialMessages?: readonly AgentMessage[];
|
|
71
|
+
/**
|
|
72
|
+
* Override for `AgentRuntimeConfig.systemPrompt` — useful when
|
|
73
|
+
* the caller has composed additional guidance (e.g. via
|
|
74
|
+
* `LocalRuntimeHost.composeSystemPrompt`). Defaults to
|
|
75
|
+
* `agentConfig.systemPrompt`.
|
|
76
|
+
*/
|
|
77
|
+
readonly systemPrompt?: string;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Produce an `AgentRuntimeConfig` per PLAN.md §3.2.1 mapping.
|
|
82
|
+
*/
|
|
83
|
+
export function createAgentRuntimeConfig(
|
|
84
|
+
input: CreateAgentRuntimeConfigInput,
|
|
85
|
+
): AgentRuntimeConfig {
|
|
86
|
+
const { agentConfig } = input;
|
|
87
|
+
|
|
88
|
+
const modelOptions = buildModelOptions(agentConfig);
|
|
89
|
+
const messageModelInfo = buildMessageModelInfo(agentConfig);
|
|
90
|
+
const hooks = input.hookBridge?.toRuntimeHooks();
|
|
91
|
+
const toolExecution = resolveToolExecution(agentConfig.maxParallelToolCalls);
|
|
92
|
+
|
|
93
|
+
const config: AgentRuntimeConfig = {
|
|
94
|
+
sessionId: input.sessionId ?? agentConfig.sessionId,
|
|
95
|
+
agentId: input.agentId,
|
|
96
|
+
conversationId: input.conversationId,
|
|
97
|
+
agentRole: input.agentRole,
|
|
98
|
+
systemPrompt: input.systemPrompt ?? agentConfig.systemPrompt,
|
|
99
|
+
messageModelInfo,
|
|
100
|
+
model: input.model,
|
|
101
|
+
modelOptions,
|
|
102
|
+
tools: input.tools,
|
|
103
|
+
hooks,
|
|
104
|
+
plugins: input.plugins,
|
|
105
|
+
logger: input.logger ?? agentConfig.logger,
|
|
106
|
+
telemetry: input.telemetry ?? mapTelemetry(agentConfig.telemetry),
|
|
107
|
+
initialMessages: input.initialMessages,
|
|
108
|
+
maxIterations: agentConfig.maxIterations,
|
|
109
|
+
toolExecution,
|
|
110
|
+
toolPolicies: agentConfig.toolPolicies,
|
|
111
|
+
requestToolApproval: agentConfig.requestToolApproval,
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
return config;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// =============================================================================
|
|
118
|
+
// Helpers
|
|
119
|
+
// =============================================================================
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Collect the provider-/reasoning-related fields from `AgentConfig`
|
|
123
|
+
* into `AgentRuntimeConfig.modelOptions`. Kept undefined when every
|
|
124
|
+
* field is undefined so the runtime does not receive an empty object.
|
|
125
|
+
*/
|
|
126
|
+
export function buildModelOptions(
|
|
127
|
+
config: AgentConfig,
|
|
128
|
+
): Record<string, unknown> | undefined {
|
|
129
|
+
const options: Record<string, unknown> = {};
|
|
130
|
+
if (config.thinking !== undefined) {
|
|
131
|
+
options.thinking = config.thinking;
|
|
132
|
+
}
|
|
133
|
+
if (config.reasoningEffort !== undefined) {
|
|
134
|
+
options.reasoningEffort = config.reasoningEffort;
|
|
135
|
+
}
|
|
136
|
+
if (config.thinkingBudgetTokens !== undefined) {
|
|
137
|
+
options.thinkingBudgetTokens = config.thinkingBudgetTokens;
|
|
138
|
+
}
|
|
139
|
+
if (config.maxTokensPerTurn !== undefined) {
|
|
140
|
+
options.maxTokensPerTurn = config.maxTokensPerTurn;
|
|
141
|
+
}
|
|
142
|
+
if (config.apiTimeoutMs !== undefined) {
|
|
143
|
+
options.apiTimeoutMs = config.apiTimeoutMs;
|
|
144
|
+
}
|
|
145
|
+
return Object.keys(options).length > 0 ? options : undefined;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Compose `messageModelInfo` from the provider-related fields per
|
|
150
|
+
* §3.2.1: `{ id: modelId, provider: providerId, family:
|
|
151
|
+
* providerConfig?.family }`.
|
|
152
|
+
*/
|
|
153
|
+
export function buildMessageModelInfo(
|
|
154
|
+
config: AgentConfig,
|
|
155
|
+
): AgentMessage["modelInfo"] {
|
|
156
|
+
const family = (config.providerConfig as { family?: string } | undefined)
|
|
157
|
+
?.family;
|
|
158
|
+
return {
|
|
159
|
+
id: config.modelId,
|
|
160
|
+
provider: config.providerId,
|
|
161
|
+
family,
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* `"parallel"` when `maxParallelToolCalls ≥ 2`, `"sequential"` when
|
|
167
|
+
* `1`, `undefined` when the caller did not specify.
|
|
168
|
+
*/
|
|
169
|
+
export function resolveToolExecution(
|
|
170
|
+
maxParallelToolCalls: number | undefined,
|
|
171
|
+
): "sequential" | "parallel" | undefined {
|
|
172
|
+
if (maxParallelToolCalls === undefined) {
|
|
173
|
+
return undefined;
|
|
174
|
+
}
|
|
175
|
+
return maxParallelToolCalls >= 2 ? "parallel" : "sequential";
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Adapt the full `ITelemetryService` to the minimal `AgentTelemetry`
|
|
180
|
+
* shape. The runtime only calls `capture(event, properties)`; the
|
|
181
|
+
* remaining methods are host concerns and stay on the
|
|
182
|
+
* `ITelemetryService` instance owned by `SessionRuntime`.
|
|
183
|
+
*/
|
|
184
|
+
export function mapTelemetry(
|
|
185
|
+
telemetry: AgentConfig["telemetry"],
|
|
186
|
+
): AgentTelemetry | undefined {
|
|
187
|
+
if (!telemetry) {
|
|
188
|
+
return undefined;
|
|
189
|
+
}
|
|
190
|
+
return {
|
|
191
|
+
capture: (event, properties) => {
|
|
192
|
+
// The runtime's `AgentTelemetry.capture` signature uses
|
|
193
|
+
// `Record<string, unknown>`, which is wider than
|
|
194
|
+
// `TelemetryProperties`. We cast at the boundary — any
|
|
195
|
+
// non-telemetry-compatible values are ignored by the
|
|
196
|
+
// underlying service.
|
|
197
|
+
telemetry.capture({
|
|
198
|
+
event,
|
|
199
|
+
properties: properties as
|
|
200
|
+
| Parameters<typeof telemetry.capture>[0]["properties"]
|
|
201
|
+
| undefined,
|
|
202
|
+
});
|
|
203
|
+
},
|
|
204
|
+
};
|
|
205
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure error-classification and tool-call-feedback helpers.
|
|
3
|
+
*
|
|
4
|
+
* @see PLAN.md §3.1 — moved from `packages/agents/src/api/error-handling.ts` lines 20–145.
|
|
5
|
+
*
|
|
6
|
+
* Consumed by `SessionRuntime` (and `MistakeTracker`) when composing
|
|
7
|
+
* follow-up turns after API failures or invalid tool calls.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type * as LlmsProviders from "@clinebot/llms";
|
|
11
|
+
import type { ToolCallRecord } from "@clinebot/shared";
|
|
12
|
+
|
|
13
|
+
// =============================================================================
|
|
14
|
+
// API Error Classification
|
|
15
|
+
// =============================================================================
|
|
16
|
+
|
|
17
|
+
const NON_RECOVERABLE_STATUS_CODES = [
|
|
18
|
+
400, 401, 402, 403, 404, 405, 406, 409, 410, 429,
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
const NON_RECOVERABLE_PHRASES = [
|
|
22
|
+
"not found",
|
|
23
|
+
"unsupported for",
|
|
24
|
+
"missing api key",
|
|
25
|
+
"invalid api key",
|
|
26
|
+
"authentication",
|
|
27
|
+
"unauthorized",
|
|
28
|
+
"forbidden",
|
|
29
|
+
"overloaded",
|
|
30
|
+
"insufficient balance",
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
export function isNonRecoverableApiError(error: Error): boolean {
|
|
34
|
+
const message = error.message.toLowerCase();
|
|
35
|
+
|
|
36
|
+
if (
|
|
37
|
+
NON_RECOVERABLE_STATUS_CODES.some((code) =>
|
|
38
|
+
new RegExp(`(?:\\b|\\"code\\"\\s*:\\s*)${code}(?:\\b|\\s)`).test(message),
|
|
39
|
+
)
|
|
40
|
+
) {
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (NON_RECOVERABLE_PHRASES.some((s) => message.includes(s))) {
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// =============================================================================
|
|
52
|
+
// Invalid Tool Call Feedback
|
|
53
|
+
// =============================================================================
|
|
54
|
+
|
|
55
|
+
export interface InvalidToolCall {
|
|
56
|
+
id: string;
|
|
57
|
+
name?: string;
|
|
58
|
+
input?: unknown;
|
|
59
|
+
reason: "missing_name" | "missing_arguments" | "invalid_arguments";
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function extractParseError(input: unknown): string | undefined {
|
|
63
|
+
if (
|
|
64
|
+
input &&
|
|
65
|
+
typeof input === "object" &&
|
|
66
|
+
!Array.isArray(input) &&
|
|
67
|
+
typeof (input as { parse_error?: unknown }).parse_error === "string"
|
|
68
|
+
) {
|
|
69
|
+
return (input as { parse_error: string }).parse_error;
|
|
70
|
+
}
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function buildInvalidToolCallFeedback(
|
|
75
|
+
invalidToolCalls: readonly InvalidToolCall[],
|
|
76
|
+
): string {
|
|
77
|
+
const details = invalidToolCalls
|
|
78
|
+
.map((call) => {
|
|
79
|
+
const name = call.name?.trim() || "(unknown tool)";
|
|
80
|
+
const parseError = extractParseError(call.input);
|
|
81
|
+
const reason =
|
|
82
|
+
call.reason === "missing_name"
|
|
83
|
+
? "missing tool name"
|
|
84
|
+
: call.reason === "missing_arguments"
|
|
85
|
+
? "missing arguments"
|
|
86
|
+
: (parseError ?? "arguments could not be parsed as JSON");
|
|
87
|
+
return `${name} [${call.id}]: ${reason}`;
|
|
88
|
+
})
|
|
89
|
+
.join("; ");
|
|
90
|
+
return `One or more tool calls were invalid or missing required parameters (${details}). Retry with valid tool names and arguments.`;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function buildInvalidToolResultMessage(
|
|
94
|
+
invalidToolCalls: readonly InvalidToolCall[],
|
|
95
|
+
): LlmsProviders.Message {
|
|
96
|
+
return {
|
|
97
|
+
role: "user",
|
|
98
|
+
content: invalidToolCalls.map((call) => ({
|
|
99
|
+
type: "tool_result" as const,
|
|
100
|
+
tool_use_id: call.id,
|
|
101
|
+
content: JSON.stringify({
|
|
102
|
+
toolName: call.name?.trim() || "(unknown tool)",
|
|
103
|
+
query: call.input ?? {},
|
|
104
|
+
result: "",
|
|
105
|
+
error:
|
|
106
|
+
call.reason === "missing_name"
|
|
107
|
+
? "Tool call was missing a tool name"
|
|
108
|
+
: call.reason === "missing_arguments"
|
|
109
|
+
? "Tool call was missing required arguments"
|
|
110
|
+
: (extractParseError(call.input) ??
|
|
111
|
+
"Tool call arguments could not be parsed as JSON"),
|
|
112
|
+
success: false,
|
|
113
|
+
}),
|
|
114
|
+
is_error: true,
|
|
115
|
+
})),
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// =============================================================================
|
|
120
|
+
// Failed Tool Call Feedback
|
|
121
|
+
// =============================================================================
|
|
122
|
+
|
|
123
|
+
export function buildFailedToolCallFeedback(
|
|
124
|
+
toolResults: readonly ToolCallRecord[],
|
|
125
|
+
): string {
|
|
126
|
+
const failed = toolResults.filter((record) => !!record.error);
|
|
127
|
+
if (failed.length === 0) {
|
|
128
|
+
return "";
|
|
129
|
+
}
|
|
130
|
+
const details = failed
|
|
131
|
+
.slice(0, 3)
|
|
132
|
+
.map((record) => {
|
|
133
|
+
const message = String(record.error ?? "unknown tool error")
|
|
134
|
+
.replace(/\s+/g, " ")
|
|
135
|
+
.trim();
|
|
136
|
+
return `${record.name}: ${message}`;
|
|
137
|
+
})
|
|
138
|
+
.join("; ");
|
|
139
|
+
return failed.length > 3
|
|
140
|
+
? `${details}; +${failed.length - 3} more failed tool call(s)`
|
|
141
|
+
: details;
|
|
142
|
+
}
|
package/src/runtime/history.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
|
+
import { readdir, readFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
1
3
|
import type * as LlmsProviders from "@clinebot/llms";
|
|
2
4
|
import { formatDisplayUserInput, normalizeUserInput } from "@clinebot/shared";
|
|
5
|
+
import { resolveSessionDataDir } from "@clinebot/shared/storage";
|
|
6
|
+
import type { SessionManifest } from "../session/session-manifest";
|
|
7
|
+
import { SessionManifestSchema } from "../session/session-manifest";
|
|
3
8
|
import type {
|
|
4
9
|
SessionHistoryMetadata,
|
|
5
10
|
SessionHistoryRecord,
|
|
@@ -7,6 +12,12 @@ import type {
|
|
|
7
12
|
} from "../types/sessions";
|
|
8
13
|
import type { RuntimeHost } from "./runtime-host";
|
|
9
14
|
|
|
15
|
+
export interface SessionHistoryListOptions {
|
|
16
|
+
limit?: number;
|
|
17
|
+
includeManifestFallback?: boolean;
|
|
18
|
+
hydrate?: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
10
21
|
type StoredSessionMessage = LlmsProviders.Message & {
|
|
11
22
|
metrics?: {
|
|
12
23
|
cost?: number;
|
|
@@ -51,6 +62,103 @@ function asHistoryMetadata(value: unknown): SessionHistoryMetadata | undefined {
|
|
|
51
62
|
return { ...(value as Record<string, unknown>) };
|
|
52
63
|
}
|
|
53
64
|
|
|
65
|
+
function normalizeHistoryLimit(limit: number | undefined): number {
|
|
66
|
+
const value = limit ?? 200;
|
|
67
|
+
return Number.isFinite(value) ? Math.max(0, Math.floor(value)) : 200;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function extractSessionRecencyToken(sessionId: string): number {
|
|
71
|
+
const matches = sessionId.match(/\d{13,}/g);
|
|
72
|
+
if (!matches || matches.length === 0) {
|
|
73
|
+
return 0;
|
|
74
|
+
}
|
|
75
|
+
let best = 0;
|
|
76
|
+
for (const match of matches) {
|
|
77
|
+
const value = Number.parseInt(match, 10);
|
|
78
|
+
if (Number.isFinite(value) && value > best) {
|
|
79
|
+
best = value;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return best;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function manifestToSessionRecord(manifest: SessionManifest): SessionRecord {
|
|
86
|
+
return {
|
|
87
|
+
sessionId: manifest.session_id,
|
|
88
|
+
source: manifest.source,
|
|
89
|
+
pid: manifest.pid,
|
|
90
|
+
startedAt: manifest.started_at,
|
|
91
|
+
endedAt: manifest.ended_at ?? null,
|
|
92
|
+
exitCode: manifest.exit_code ?? null,
|
|
93
|
+
status: manifest.status,
|
|
94
|
+
interactive: manifest.interactive,
|
|
95
|
+
provider: manifest.provider,
|
|
96
|
+
model: manifest.model,
|
|
97
|
+
cwd: manifest.cwd,
|
|
98
|
+
workspaceRoot: manifest.workspace_root,
|
|
99
|
+
teamName: manifest.team_name,
|
|
100
|
+
enableTools: manifest.enable_tools,
|
|
101
|
+
enableSpawn: manifest.enable_spawn,
|
|
102
|
+
enableTeams: manifest.enable_teams,
|
|
103
|
+
isSubagent: false,
|
|
104
|
+
prompt: manifest.prompt,
|
|
105
|
+
metadata: manifest.metadata,
|
|
106
|
+
messagesPath: manifest.messages_path,
|
|
107
|
+
updatedAt: manifest.ended_at ?? manifest.started_at,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async function listManifestHistoryRows(
|
|
112
|
+
limit: number,
|
|
113
|
+
): Promise<SessionRecord[]> {
|
|
114
|
+
const requestedLimit = normalizeHistoryLimit(limit);
|
|
115
|
+
const sessionsDir = resolveSessionDataDir();
|
|
116
|
+
const entries = await readdir(sessionsDir, { withFileTypes: true }).catch(
|
|
117
|
+
() => [],
|
|
118
|
+
);
|
|
119
|
+
const candidateEntries = entries
|
|
120
|
+
.filter((entry) => entry.isDirectory())
|
|
121
|
+
.map((entry) => ({
|
|
122
|
+
entry,
|
|
123
|
+
recency: extractSessionRecencyToken(entry.name.trim()),
|
|
124
|
+
}))
|
|
125
|
+
.sort(
|
|
126
|
+
(left, right) =>
|
|
127
|
+
right.recency - left.recency ||
|
|
128
|
+
right.entry.name.localeCompare(left.entry.name),
|
|
129
|
+
)
|
|
130
|
+
.slice(0, requestedLimit);
|
|
131
|
+
const rows = await Promise.all(
|
|
132
|
+
candidateEntries.map(async ({ entry }) => {
|
|
133
|
+
const sessionId = entry.name.trim();
|
|
134
|
+
if (!sessionId) {
|
|
135
|
+
return undefined;
|
|
136
|
+
}
|
|
137
|
+
const manifestPath = join(sessionsDir, sessionId, `${sessionId}.json`);
|
|
138
|
+
const raw = await readFile(manifestPath, "utf8").catch(() => undefined);
|
|
139
|
+
if (!raw) {
|
|
140
|
+
return undefined;
|
|
141
|
+
}
|
|
142
|
+
let parsedJson: unknown;
|
|
143
|
+
try {
|
|
144
|
+
parsedJson = JSON.parse(raw) as unknown;
|
|
145
|
+
} catch {
|
|
146
|
+
return undefined;
|
|
147
|
+
}
|
|
148
|
+
const parsedManifest = SessionManifestSchema.safeParse(parsedJson);
|
|
149
|
+
if (!parsedManifest.success) {
|
|
150
|
+
return undefined;
|
|
151
|
+
}
|
|
152
|
+
return manifestToSessionRecord(parsedManifest.data);
|
|
153
|
+
}),
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
return rows
|
|
157
|
+
.filter((row): row is SessionRecord => Boolean(row))
|
|
158
|
+
.sort((left, right) => right.startedAt.localeCompare(left.startedAt))
|
|
159
|
+
.slice(0, requestedLimit);
|
|
160
|
+
}
|
|
161
|
+
|
|
54
162
|
function extractTextFromContent(
|
|
55
163
|
content: LlmsProviders.Message["content"],
|
|
56
164
|
): string {
|
|
@@ -235,3 +343,32 @@ export async function hydrateSessionHistory(
|
|
|
235
343
|
}),
|
|
236
344
|
);
|
|
237
345
|
}
|
|
346
|
+
|
|
347
|
+
export async function listSessionHistory(
|
|
348
|
+
host: Pick<RuntimeHost, "list" | "readMessages">,
|
|
349
|
+
options: SessionHistoryListOptions = {},
|
|
350
|
+
): Promise<SessionHistoryRecord[]> {
|
|
351
|
+
const limit = normalizeHistoryLimit(options.limit);
|
|
352
|
+
const backendRows = (await host.list(limit)).slice(0, limit);
|
|
353
|
+
const manifestRows =
|
|
354
|
+
options.includeManifestFallback === true && backendRows.length < limit
|
|
355
|
+
? await listManifestHistoryRows(Math.min(Math.max(limit * 2, 100), 500))
|
|
356
|
+
: [];
|
|
357
|
+
const merged = new Map<string, SessionRecord>();
|
|
358
|
+
for (const row of [...backendRows, ...manifestRows]) {
|
|
359
|
+
if (merged.has(row.sessionId)) {
|
|
360
|
+
continue;
|
|
361
|
+
}
|
|
362
|
+
merged.set(row.sessionId, row);
|
|
363
|
+
}
|
|
364
|
+
const rows =
|
|
365
|
+
manifestRows.length === 0
|
|
366
|
+
? backendRows
|
|
367
|
+
: Array.from(merged.values())
|
|
368
|
+
.sort((left, right) => right.startedAt.localeCompare(left.startedAt))
|
|
369
|
+
.slice(0, limit);
|
|
370
|
+
if (options.hydrate === false) {
|
|
371
|
+
return rows.map((row) => normalizeHistoryRow(row));
|
|
372
|
+
}
|
|
373
|
+
return await hydrateSessionHistory(host, rows);
|
|
374
|
+
}
|
package/src/runtime/host.ts
CHANGED
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
ensureCompatibleLocalHubUrl,
|
|
4
4
|
resolveCompatibleLocalHubUrl,
|
|
5
5
|
} from "../hub/client";
|
|
6
|
+
import { prewarmDetachedHubServer } from "../hub/daemon";
|
|
6
7
|
import { SqliteSessionStore } from "../services/storage/sqlite-session-store";
|
|
7
8
|
import { resolveCoreDistinctId } from "../services/telemetry/distinct-id";
|
|
8
9
|
import { FileSessionService } from "../session/file-session-service";
|
|
@@ -33,6 +34,23 @@ export type SessionBackend = CoreSessionService | FileSessionService;
|
|
|
33
34
|
let cachedBackend: SessionBackend | undefined;
|
|
34
35
|
let backendInitPromise: Promise<SessionBackend> | undefined;
|
|
35
36
|
|
|
37
|
+
function prewarmLocalHubIfNeeded(
|
|
38
|
+
configuredMode: RuntimeHostMode,
|
|
39
|
+
options: ClineCoreOptions,
|
|
40
|
+
): void {
|
|
41
|
+
if (configuredMode !== "auto" && configuredMode !== "hub") {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
if (options.hub?.endpoint?.trim()) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
prewarmDetachedHubServer(
|
|
48
|
+
options.hub?.workspaceRoot?.trim() ||
|
|
49
|
+
options.hub?.cwd?.trim() ||
|
|
50
|
+
process.cwd(),
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
36
54
|
async function reconcileDeadSessionsIfSupported(
|
|
37
55
|
backend: SessionBackend,
|
|
38
56
|
): Promise<void> {
|
|
@@ -108,6 +126,7 @@ export async function createRuntimeHost(
|
|
|
108
126
|
const distinctId = resolveCoreDistinctId(options.distinctId);
|
|
109
127
|
options.telemetry?.setDistinctId(distinctId);
|
|
110
128
|
const configuredMode = resolveConfiguredBackendMode(options);
|
|
129
|
+
prewarmLocalHubIfNeeded(configuredMode, options);
|
|
111
130
|
if (configuredMode === "remote") {
|
|
112
131
|
const remoteEndpoint = options.remote?.endpoint?.trim();
|
|
113
132
|
if (!remoteEndpoint) {
|
|
@@ -125,6 +144,7 @@ export async function createRuntimeHost(
|
|
|
125
144
|
displayName: options.remote?.displayName,
|
|
126
145
|
workspaceRoot: options.remote?.workspaceRoot,
|
|
127
146
|
cwd: options.remote?.cwd,
|
|
147
|
+
requestToolApproval: options.requestToolApproval,
|
|
128
148
|
});
|
|
129
149
|
}
|
|
130
150
|
if (configuredMode === "hub") {
|
|
@@ -149,6 +169,7 @@ export async function createRuntimeHost(
|
|
|
149
169
|
authToken: options.hub?.authToken,
|
|
150
170
|
clientType: options.hub?.clientType,
|
|
151
171
|
displayName: options.hub?.displayName,
|
|
172
|
+
requestToolApproval: options.requestToolApproval,
|
|
152
173
|
},
|
|
153
174
|
{
|
|
154
175
|
workspaceRoot: options.hub?.workspaceRoot,
|
|
@@ -173,6 +194,7 @@ export async function createRuntimeHost(
|
|
|
173
194
|
authToken: options.hub?.authToken,
|
|
174
195
|
clientType: options.hub?.clientType,
|
|
175
196
|
displayName: options.hub?.displayName,
|
|
197
|
+
requestToolApproval: options.requestToolApproval,
|
|
176
198
|
},
|
|
177
199
|
{
|
|
178
200
|
workspaceRoot: options.hub?.workspaceRoot,
|