@clinebot/core 0.0.27 → 0.0.29
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/README.md +7 -0
- package/dist/ClineCore.d.ts +28 -2
- package/dist/ClineCore.d.ts.map +1 -1
- package/dist/account/cline-account-service.d.ts +1 -1
- package/dist/account/cline-account-service.d.ts.map +1 -1
- package/dist/account/index.d.ts +1 -1
- package/dist/account/index.d.ts.map +1 -1
- package/dist/account/types.d.ts +5 -0
- package/dist/account/types.d.ts.map +1 -1
- package/dist/auth/bounded-ttl-cache.d.ts +14 -0
- package/dist/auth/bounded-ttl-cache.d.ts.map +1 -0
- package/dist/auth/cline.d.ts +27 -2
- package/dist/auth/cline.d.ts.map +1 -1
- package/dist/auth/oca.d.ts.map +1 -1
- package/dist/chat/chat-schema.d.ts +8 -8
- package/dist/extensions/config/agent-config-loader.d.ts.map +1 -0
- package/dist/{agents → extensions/config}/agent-config-parser.d.ts +2 -2
- package/dist/extensions/config/agent-config-parser.d.ts.map +1 -0
- package/dist/{agents → extensions/config}/hooks-config-loader.d.ts +1 -1
- package/dist/extensions/config/hooks-config-loader.d.ts.map +1 -0
- package/dist/{agents → extensions/config}/index.d.ts +2 -4
- package/dist/extensions/config/index.d.ts.map +1 -0
- package/dist/{runtime/commands.d.ts → extensions/config/runtime-commands.d.ts} +2 -3
- package/dist/extensions/config/runtime-commands.d.ts.map +1 -0
- package/dist/extensions/config/unified-config-file-watcher.d.ts.map +1 -0
- package/dist/extensions/config/user-instruction-config-loader.d.ts.map +1 -0
- package/dist/extensions/context/agentic-compaction.d.ts +13 -0
- package/dist/extensions/context/agentic-compaction.d.ts.map +1 -0
- package/dist/extensions/context/basic-compaction.d.ts +9 -0
- package/dist/extensions/context/basic-compaction.d.ts.map +1 -0
- package/dist/extensions/context/compaction-shared.d.ts +60 -0
- package/dist/extensions/context/compaction-shared.d.ts.map +1 -0
- package/dist/extensions/context/compaction.d.ts +20 -0
- package/dist/extensions/context/compaction.d.ts.map +1 -0
- package/dist/extensions/index.d.ts +5 -0
- package/dist/extensions/index.d.ts.map +1 -0
- package/dist/extensions/mcp/client.d.ts +3 -0
- package/dist/extensions/mcp/client.d.ts.map +1 -0
- package/dist/extensions/mcp/config-loader.d.ts.map +1 -0
- package/dist/extensions/mcp/index.d.ts +9 -0
- package/dist/extensions/mcp/index.d.ts.map +1 -0
- package/dist/{mcp → extensions/mcp}/manager.d.ts +1 -2
- package/dist/extensions/mcp/manager.d.ts.map +1 -0
- package/dist/extensions/mcp/name-transform.d.ts +3 -0
- package/dist/extensions/mcp/name-transform.d.ts.map +1 -0
- package/dist/extensions/mcp/policies.d.ts +15 -0
- package/dist/extensions/mcp/policies.d.ts.map +1 -0
- package/dist/extensions/mcp/tools.d.ts +4 -0
- package/dist/extensions/mcp/tools.d.ts.map +1 -0
- package/dist/{mcp → extensions/mcp}/types.d.ts +29 -1
- package/dist/extensions/mcp/types.d.ts.map +1 -0
- package/dist/{agents → extensions/plugin}/plugin-config-loader.d.ts +1 -1
- package/dist/extensions/plugin/plugin-config-loader.d.ts.map +1 -0
- package/dist/{agents → extensions/plugin}/plugin-loader.d.ts +1 -1
- package/dist/extensions/plugin/plugin-loader.d.ts.map +1 -0
- package/dist/extensions/plugin/plugin-module-import.d.ts +5 -0
- package/dist/extensions/plugin/plugin-module-import.d.ts.map +1 -0
- package/dist/{agents → extensions/plugin}/plugin-sandbox.d.ts +1 -1
- package/dist/extensions/plugin/plugin-sandbox.d.ts.map +1 -0
- package/dist/extensions/plugin-sandbox-bootstrap.js +485 -0
- package/dist/hooks/index.d.ts +4 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/persistent.d.ts +64 -0
- package/dist/hooks/persistent.d.ts.map +1 -0
- package/dist/hooks/subprocess-runner.d.ts +22 -0
- package/dist/hooks/subprocess-runner.d.ts.map +1 -0
- package/dist/hooks/subprocess.d.ts +189 -0
- package/dist/hooks/subprocess.d.ts.map +1 -0
- package/dist/index.d.ts +22 -25
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +560 -447
- package/dist/prompt/default-system.d.ts +2 -0
- package/dist/prompt/default-system.d.ts.map +1 -0
- package/dist/providers/local-provider-service.d.ts +1 -1
- package/dist/providers/local-provider-service.d.ts.map +1 -1
- package/dist/runtime/checkpoint-hooks.d.ts +21 -0
- package/dist/runtime/checkpoint-hooks.d.ts.map +1 -0
- package/dist/runtime/hook-file-hooks.d.ts +1 -1
- package/dist/runtime/hook-file-hooks.d.ts.map +1 -1
- package/dist/runtime/rules.d.ts +1 -1
- package/dist/runtime/rules.d.ts.map +1 -1
- package/dist/runtime/runtime-builder.d.ts +1 -1
- package/dist/runtime/runtime-builder.d.ts.map +1 -1
- package/dist/runtime/session-runtime.d.ts +25 -5
- package/dist/runtime/session-runtime.d.ts.map +1 -1
- package/dist/runtime/subprocess-sandbox.d.ts.map +1 -0
- package/dist/runtime/team-runtime-registry.d.ts +1 -1
- package/dist/runtime/team-runtime-registry.d.ts.map +1 -1
- package/dist/runtime/tool-approval.d.ts +1 -1
- package/dist/session/default-session-manager.d.ts +4 -3
- package/dist/session/default-session-manager.d.ts.map +1 -1
- package/dist/session/file-session-service.d.ts +1 -1
- package/dist/session/file-session-service.d.ts.map +1 -1
- package/dist/session/{unified-session-persistence-service.d.ts → persistence-service.d.ts} +11 -42
- package/dist/session/persistence-service.d.ts.map +1 -0
- package/dist/session/rpc-session-service.d.ts +1 -1
- package/dist/session/rpc-session-service.d.ts.map +1 -1
- package/dist/session/session-agent-events.d.ts +1 -1
- package/dist/session/session-artifacts.d.ts.map +1 -1
- package/dist/session/session-config-builder.d.ts.map +1 -1
- package/dist/session/session-graph.d.ts +1 -1
- package/dist/session/session-graph.d.ts.map +1 -1
- package/dist/session/session-host.d.ts.map +1 -1
- package/dist/session/session-manager.d.ts +6 -5
- package/dist/session/session-manager.d.ts.map +1 -1
- package/dist/session/session-manifest.d.ts +1 -1
- package/dist/session/session-service.d.ts +3 -2
- package/dist/session/session-service.d.ts.map +1 -1
- package/dist/session/session-team-coordination.d.ts +2 -1
- package/dist/session/session-team-coordination.d.ts.map +1 -1
- package/dist/session/utils/helpers.d.ts +51 -3
- package/dist/session/utils/helpers.d.ts.map +1 -1
- package/dist/session/utils/types.d.ts +41 -7
- package/dist/session/utils/types.d.ts.map +1 -1
- package/dist/session/workspace-manager.d.ts +1 -2
- package/dist/session/workspace-manager.d.ts.map +1 -1
- package/dist/session/workspace-manifest.d.ts +1 -22
- package/dist/session/workspace-manifest.d.ts.map +1 -1
- package/dist/storage/file-team-store.d.ts +2 -1
- package/dist/storage/file-team-store.d.ts.map +1 -1
- package/dist/storage/sqlite-team-store.d.ts +4 -1
- package/dist/storage/sqlite-team-store.d.ts.map +1 -1
- package/dist/storage/team-store.d.ts.map +1 -1
- package/dist/team/delegated-agent.d.ts +44 -0
- package/dist/team/delegated-agent.d.ts.map +1 -0
- package/dist/team/index.d.ts +1 -0
- package/dist/team/index.d.ts.map +1 -1
- package/dist/team/multi-agent.d.ts +229 -0
- package/dist/team/multi-agent.d.ts.map +1 -0
- package/dist/team/projections.d.ts +2 -2
- package/dist/team/projections.d.ts.map +1 -1
- package/dist/team/runtime.d.ts +5 -0
- package/dist/team/runtime.d.ts.map +1 -0
- package/dist/team/spawn-agent-tool.d.ts +85 -0
- package/dist/team/spawn-agent-tool.d.ts.map +1 -0
- package/dist/team/subagent-prompts.d.ts +4 -0
- package/dist/team/subagent-prompts.d.ts.map +1 -0
- package/dist/team/team-tools.d.ts +35 -0
- package/dist/team/team-tools.d.ts.map +1 -0
- package/dist/telemetry/OpenTelemetryProvider.d.ts +11 -1
- package/dist/telemetry/OpenTelemetryProvider.d.ts.map +1 -1
- package/dist/telemetry/{LoggerTelemetryAdapter.d.ts → TelemetryLoggerSink.d.ts} +10 -4
- package/dist/telemetry/TelemetryLoggerSink.d.ts.map +1 -0
- package/dist/telemetry/TelemetryService.d.ts.map +1 -1
- package/dist/telemetry/index.js +15 -28
- package/dist/tools/definitions.d.ts +4 -3
- package/dist/tools/definitions.d.ts.map +1 -1
- package/dist/tools/index.d.ts +5 -5
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/model-tool-routing.d.ts.map +1 -1
- package/dist/tools/presets.d.ts +26 -0
- package/dist/tools/presets.d.ts.map +1 -1
- package/dist/tools/schemas.d.ts +8 -0
- package/dist/tools/schemas.d.ts.map +1 -1
- package/dist/tools/types.d.ts +23 -2
- package/dist/tools/types.d.ts.map +1 -1
- package/dist/types/config.d.ts +47 -3
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/events.d.ts +1 -1
- package/dist/types/provider-settings.d.ts +1 -1
- package/dist/types/provider-settings.d.ts.map +1 -1
- package/dist/types/storage.d.ts +2 -1
- package/dist/types/storage.d.ts.map +1 -1
- package/dist/types.d.ts +7 -16
- package/dist/types.d.ts.map +1 -1
- package/package.json +16 -13
- package/src/ClineCore.test.ts +150 -0
- package/src/ClineCore.ts +114 -8
- package/src/account/cline-account-service.test.ts +84 -0
- package/src/account/cline-account-service.ts +2 -2
- package/src/account/index.ts +1 -0
- package/src/account/types.ts +6 -0
- package/src/auth/bounded-ttl-cache.test.ts +38 -0
- package/src/auth/bounded-ttl-cache.ts +53 -0
- package/src/auth/cline.test.ts +173 -36
- package/src/auth/cline.ts +395 -93
- package/src/auth/oca.test.ts +125 -0
- package/src/auth/oca.ts +17 -4
- package/src/{agents → extensions/config}/agent-config-loader.test.ts +1 -1
- package/src/{agents → extensions/config}/agent-config-parser.ts +2 -2
- package/src/{agents → extensions/config}/hooks-config-loader.ts +1 -1
- package/src/{agents → extensions/config}/index.ts +7 -11
- package/src/{runtime/commands.test.ts → extensions/config/runtime-commands.test.ts} +20 -3
- package/src/{runtime/commands.ts → extensions/config/runtime-commands.ts} +1 -8
- package/src/{agents → extensions/config}/unified-config-file-watcher.ts +15 -2
- package/src/{agents → extensions/config}/user-instruction-config-loader.test.ts +90 -2
- package/src/{agents → extensions/config}/user-instruction-config-loader.ts +126 -12
- package/src/extensions/context/agentic-compaction.ts +119 -0
- package/src/extensions/context/basic-compaction.ts +275 -0
- package/src/extensions/context/compaction-shared.ts +458 -0
- package/src/extensions/context/compaction.test.ts +477 -0
- package/src/extensions/context/compaction.ts +203 -0
- package/src/extensions/index.ts +12 -0
- package/src/extensions/mcp/client.ts +420 -0
- package/src/{mcp → extensions/mcp}/index.ts +16 -0
- package/src/{mcp → extensions/mcp}/manager.test.ts +1 -2
- package/src/{mcp → extensions/mcp}/manager.ts +3 -5
- package/src/extensions/mcp/name-transform.ts +33 -0
- package/src/extensions/mcp/policies.ts +47 -0
- package/src/extensions/mcp/tools.ts +47 -0
- package/src/{mcp → extensions/mcp}/types.ts +35 -7
- package/src/{agents → extensions/plugin}/plugin-config-loader.test.ts +18 -13
- package/src/{agents → extensions/plugin}/plugin-config-loader.ts +1 -1
- package/src/{agents → extensions/plugin}/plugin-loader.test.ts +41 -4
- package/src/extensions/plugin/plugin-loader.ts +106 -0
- package/src/extensions/plugin/plugin-module-import.ts +278 -0
- package/src/{agents → extensions/plugin}/plugin-sandbox-bootstrap.ts +30 -92
- package/src/{agents → extensions/plugin}/plugin-sandbox.test.ts +60 -3
- package/src/{agents → extensions/plugin}/plugin-sandbox.ts +146 -56
- package/src/hooks/index.ts +25 -0
- package/src/hooks/persistent.ts +661 -0
- package/src/hooks/subprocess-runner.ts +196 -0
- package/src/hooks/subprocess.ts +669 -0
- package/src/index.ts +200 -118
- package/src/prompt/default-system.ts +21 -0
- package/src/providers/local-provider-registry.ts +1 -1
- package/src/providers/local-provider-service.test.ts +23 -2
- package/src/providers/local-provider-service.ts +2 -2
- package/src/runtime/checkpoint-hooks.test.ts +167 -0
- package/src/runtime/checkpoint-hooks.ts +186 -0
- package/src/runtime/hook-file-hooks.test.ts +40 -1
- package/src/runtime/hook-file-hooks.ts +35 -16
- package/src/runtime/index.ts +4 -19
- package/src/runtime/rules.ts +4 -1
- package/src/runtime/runtime-builder.team-persistence.test.ts +3 -6
- package/src/runtime/runtime-builder.test.ts +266 -160
- package/src/runtime/runtime-builder.ts +120 -47
- package/src/runtime/runtime-parity.test.ts +22 -22
- package/src/runtime/session-runtime.ts +36 -6
- package/src/runtime/{sandbox/subprocess-sandbox.ts → subprocess-sandbox.ts} +24 -3
- package/src/runtime/team-runtime-registry.ts +1 -4
- package/src/runtime/tool-approval.ts +1 -1
- package/src/session/default-session-manager.e2e.test.ts +2 -2
- package/src/session/default-session-manager.test.ts +553 -9
- package/src/session/default-session-manager.ts +140 -46
- package/src/session/file-session-service.ts +3 -3
- package/src/session/index.ts +6 -6
- package/src/session/persistence-service.test.ts +212 -0
- package/src/session/{unified-session-persistence-service.ts → persistence-service.ts} +106 -172
- package/src/session/rpc-session-service.ts +3 -3
- package/src/session/runtime-oauth-token-manager.ts +1 -1
- package/src/session/session-agent-events.ts +1 -1
- package/src/session/session-artifacts.ts +32 -4
- package/src/session/session-config-builder.ts +22 -9
- package/src/session/session-graph.ts +1 -1
- package/src/session/session-host.ts +19 -11
- package/src/session/session-manager.ts +11 -6
- package/src/session/session-service.team-persistence.test.ts +1 -1
- package/src/session/session-service.ts +6 -9
- package/src/session/session-team-coordination.ts +7 -3
- package/src/session/session-telemetry.ts +1 -1
- package/src/session/utils/helpers.test.ts +160 -0
- package/src/session/utils/helpers.ts +289 -42
- package/src/session/utils/types.ts +47 -7
- package/src/session/workspace-manager.ts +5 -3
- package/src/session/workspace-manifest.ts +3 -49
- package/src/storage/file-team-store.ts +2 -5
- package/src/storage/provider-settings-legacy-migration.ts +2 -2
- package/src/storage/provider-settings-manager.test.ts +1 -1
- package/src/storage/sqlite-team-store.ts +212 -125
- package/src/storage/team-store.ts +1 -5
- package/src/team/delegated-agent.ts +131 -0
- package/src/team/index.ts +1 -0
- package/src/team/multi-agent.lifecycle.test.ts +201 -0
- package/src/team/multi-agent.ts +1666 -0
- package/src/team/projections.ts +2 -4
- package/src/team/runtime.ts +54 -0
- package/src/team/spawn-agent-tool.test.ts +387 -0
- package/src/team/spawn-agent-tool.ts +207 -0
- package/src/team/subagent-prompts.ts +41 -0
- package/src/team/team-tools.test.ts +802 -0
- package/src/team/team-tools.ts +792 -0
- package/src/telemetry/OpenTelemetryProvider.test.ts +25 -3
- package/src/telemetry/OpenTelemetryProvider.ts +108 -18
- package/src/telemetry/TelemetryLoggerSink.test.ts +42 -0
- package/src/telemetry/{LoggerTelemetryAdapter.ts → TelemetryLoggerSink.ts} +21 -14
- package/src/telemetry/TelemetryService.test.ts +7 -7
- package/src/telemetry/TelemetryService.ts +2 -4
- package/src/tools/definitions.test.ts +76 -0
- package/src/tools/definitions.ts +41 -2
- package/src/tools/executors/apply-patch.ts +1 -1
- package/src/tools/executors/editor.ts +1 -1
- package/src/tools/executors/file-read.ts +1 -1
- package/src/tools/executors/search.ts +1 -1
- package/src/tools/executors/web-fetch.ts +1 -1
- package/src/tools/index.ts +6 -1
- package/src/tools/model-tool-routing.ts +2 -0
- package/src/tools/presets.test.ts +8 -0
- package/src/tools/presets.ts +40 -2
- package/src/tools/schemas.ts +19 -0
- package/src/tools/types.ts +31 -2
- package/src/types/config.ts +61 -7
- package/src/types/events.ts +1 -1
- package/src/types/index.ts +0 -1
- package/src/types/provider-settings.ts +1 -1
- package/src/types/storage.ts +2 -5
- package/src/types.ts +32 -44
- package/dist/agents/agent-config-loader.d.ts.map +0 -1
- package/dist/agents/agent-config-parser.d.ts.map +0 -1
- package/dist/agents/hooks-config-loader.d.ts.map +0 -1
- package/dist/agents/index.d.ts.map +0 -1
- package/dist/agents/plugin-config-loader.d.ts.map +0 -1
- package/dist/agents/plugin-loader.d.ts.map +0 -1
- package/dist/agents/plugin-sandbox-bootstrap.js +0 -446
- package/dist/agents/plugin-sandbox.d.ts.map +0 -1
- package/dist/agents/unified-config-file-watcher.d.ts.map +0 -1
- package/dist/agents/user-instruction-config-loader.d.ts.map +0 -1
- package/dist/mcp/config-loader.d.ts.map +0 -1
- package/dist/mcp/index.d.ts +0 -5
- package/dist/mcp/index.d.ts.map +0 -1
- package/dist/mcp/manager.d.ts.map +0 -1
- package/dist/mcp/types.d.ts.map +0 -1
- package/dist/runtime/commands.d.ts.map +0 -1
- package/dist/runtime/sandbox/subprocess-sandbox.d.ts.map +0 -1
- package/dist/runtime/skills.d.ts +0 -14
- package/dist/runtime/skills.d.ts.map +0 -1
- package/dist/runtime/workflows.d.ts +0 -14
- package/dist/runtime/workflows.d.ts.map +0 -1
- package/dist/session/unified-session-persistence-service.d.ts.map +0 -1
- package/dist/telemetry/LoggerTelemetryAdapter.d.ts.map +0 -1
- package/dist/types/workspace.d.ts +0 -8
- package/dist/types/workspace.d.ts.map +0 -1
- package/src/agents/plugin-loader.ts +0 -175
- package/src/runtime/skills.ts +0 -44
- package/src/runtime/workflows.test.ts +0 -119
- package/src/runtime/workflows.ts +0 -45
- package/src/session/unified-session-persistence-service.test.ts +0 -85
- package/src/telemetry/LoggerTelemetryAdapter.test.ts +0 -42
- package/src/types/workspace.ts +0 -7
- /package/dist/{agents → extensions/config}/agent-config-loader.d.ts +0 -0
- /package/dist/{agents → extensions/config}/unified-config-file-watcher.d.ts +0 -0
- /package/dist/{agents → extensions/config}/user-instruction-config-loader.d.ts +0 -0
- /package/dist/{mcp → extensions/mcp}/config-loader.d.ts +0 -0
- /package/dist/runtime/{sandbox/subprocess-sandbox.d.ts → subprocess-sandbox.d.ts} +0 -0
- /package/src/{agents → extensions/config}/agent-config-loader.ts +0 -0
- /package/src/{agents → extensions/config}/hooks-config-loader.test.ts +0 -0
- /package/src/{agents → extensions/config}/unified-config-file-watcher.test.ts +0 -0
- /package/src/{mcp → extensions/mcp}/config-loader.test.ts +0 -0
- /package/src/{mcp → extensions/mcp}/config-loader.ts +0 -0
|
@@ -52,6 +52,29 @@ describe("createOpenTelemetryTelemetryService", () => {
|
|
|
52
52
|
await provider.dispose();
|
|
53
53
|
});
|
|
54
54
|
|
|
55
|
+
it("registers a tracer provider when tracesExporter is set", async () => {
|
|
56
|
+
const { provider } = createOpenTelemetryTelemetryService({
|
|
57
|
+
metadata: {
|
|
58
|
+
extension_version: "1.2.3",
|
|
59
|
+
cline_type: "cli",
|
|
60
|
+
platform: "terminal",
|
|
61
|
+
platform_version: process.version,
|
|
62
|
+
os_type: process.platform,
|
|
63
|
+
os_version: "unknown",
|
|
64
|
+
},
|
|
65
|
+
enabled: true,
|
|
66
|
+
tracesExporter: "console",
|
|
67
|
+
logsExporter: "console",
|
|
68
|
+
metricsExporter: "console",
|
|
69
|
+
serviceName: "cline-test",
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
expect(provider.tracerProvider).not.toBeNull();
|
|
73
|
+
const span = provider.getTracer("test").startSpan("verify.tracing");
|
|
74
|
+
span.end();
|
|
75
|
+
await provider.dispose();
|
|
76
|
+
});
|
|
77
|
+
|
|
55
78
|
it("does not create an OTEL provider when disabled", () => {
|
|
56
79
|
const providerSpy = vi.spyOn(
|
|
57
80
|
OpenTelemetryProvider.prototype,
|
|
@@ -78,8 +101,7 @@ describe("createOpenTelemetryTelemetryService", () => {
|
|
|
78
101
|
it("attaches the logger adapter when creating configured telemetry", () => {
|
|
79
102
|
const logger: BasicLogger = {
|
|
80
103
|
debug: vi.fn(),
|
|
81
|
-
|
|
82
|
-
warn: vi.fn(),
|
|
104
|
+
log: vi.fn(),
|
|
83
105
|
error: vi.fn(),
|
|
84
106
|
};
|
|
85
107
|
const { telemetry, provider } = createConfiguredTelemetryService({
|
|
@@ -101,7 +123,7 @@ describe("createOpenTelemetryTelemetryService", () => {
|
|
|
101
123
|
properties: { sessionId: "session-1" },
|
|
102
124
|
});
|
|
103
125
|
|
|
104
|
-
expect(logger.
|
|
126
|
+
expect(logger.log).toHaveBeenCalledWith(
|
|
105
127
|
"telemetry.event",
|
|
106
128
|
expect.objectContaining({
|
|
107
129
|
event: "session.started",
|
|
@@ -4,11 +4,12 @@ import type {
|
|
|
4
4
|
OpenTelemetryClientConfig,
|
|
5
5
|
TelemetryMetadata,
|
|
6
6
|
} from "@clinebot/shared";
|
|
7
|
-
import { metrics } from "@opentelemetry/api";
|
|
7
|
+
import { metrics, type Tracer, trace } from "@opentelemetry/api";
|
|
8
8
|
import { logs } from "@opentelemetry/api-logs";
|
|
9
9
|
import { OTLPLogExporter as OTLPLogExporterHttp } from "@opentelemetry/exporter-logs-otlp-http";
|
|
10
10
|
import { OTLPMetricExporter as OTLPMetricExporterHttp } from "@opentelemetry/exporter-metrics-otlp-http";
|
|
11
|
-
import {
|
|
11
|
+
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
|
|
12
|
+
import { resourceFromAttributes } from "@opentelemetry/resources";
|
|
12
13
|
import {
|
|
13
14
|
BatchLogRecordProcessor,
|
|
14
15
|
ConsoleLogRecordExporter,
|
|
@@ -21,6 +22,13 @@ import {
|
|
|
21
22
|
type MetricReader,
|
|
22
23
|
PeriodicExportingMetricReader,
|
|
23
24
|
} from "@opentelemetry/sdk-metrics";
|
|
25
|
+
import {
|
|
26
|
+
BatchSpanProcessor,
|
|
27
|
+
ConsoleSpanExporter,
|
|
28
|
+
SimpleSpanProcessor,
|
|
29
|
+
type SpanProcessor,
|
|
30
|
+
} from "@opentelemetry/sdk-trace-base";
|
|
31
|
+
import { NodeTracerProvider } from "@opentelemetry/sdk-trace-node";
|
|
24
32
|
import {
|
|
25
33
|
ATTR_SERVICE_NAME,
|
|
26
34
|
ATTR_SERVICE_VERSION,
|
|
@@ -38,13 +46,14 @@ type OpenTelemetryProtocol = "http/json";
|
|
|
38
46
|
export interface OpenTelemetryProviderOptions
|
|
39
47
|
extends Omit<
|
|
40
48
|
OpenTelemetryClientConfig,
|
|
41
|
-
"enabled" | "logsExporter" | "metricsExporter"
|
|
49
|
+
"enabled" | "logsExporter" | "metricsExporter" | "tracesExporter"
|
|
42
50
|
> {
|
|
43
51
|
serviceName?: string;
|
|
44
52
|
serviceVersion?: string;
|
|
45
53
|
enabled?: boolean;
|
|
46
54
|
logsExporter?: string | OpenTelemetryExporterKind[];
|
|
47
55
|
metricsExporter?: string | OpenTelemetryExporterKind[];
|
|
56
|
+
tracesExporter?: string | OpenTelemetryExporterKind[];
|
|
48
57
|
metricExportIntervalMs?: number;
|
|
49
58
|
logMaxQueueSize?: number;
|
|
50
59
|
logBatchSize?: number;
|
|
@@ -64,11 +73,12 @@ export interface CreateOpenTelemetryTelemetryServiceOptions
|
|
|
64
73
|
export class OpenTelemetryProvider {
|
|
65
74
|
readonly meterProvider: MeterProvider | null;
|
|
66
75
|
readonly loggerProvider: LoggerProvider | null;
|
|
76
|
+
readonly tracerProvider: NodeTracerProvider | null;
|
|
67
77
|
private readonly options: OpenTelemetryProviderOptions;
|
|
68
78
|
|
|
69
79
|
constructor(options: OpenTelemetryProviderOptions = {}) {
|
|
70
80
|
this.options = options;
|
|
71
|
-
const resource =
|
|
81
|
+
const resource = resourceFromAttributes({
|
|
72
82
|
[ATTR_SERVICE_NAME]: options.serviceName ?? "cline",
|
|
73
83
|
...(options.serviceVersion
|
|
74
84
|
? { [ATTR_SERVICE_VERSION]: options.serviceVersion }
|
|
@@ -77,6 +87,7 @@ export class OpenTelemetryProvider {
|
|
|
77
87
|
|
|
78
88
|
this.meterProvider = this.createMeterProvider(resource);
|
|
79
89
|
this.loggerProvider = this.createLoggerProvider(resource);
|
|
90
|
+
this.tracerProvider = this.createTracerProvider(resource);
|
|
80
91
|
|
|
81
92
|
if (this.meterProvider) {
|
|
82
93
|
metrics.setGlobalMeterProvider(this.meterProvider);
|
|
@@ -84,6 +95,17 @@ export class OpenTelemetryProvider {
|
|
|
84
95
|
if (this.loggerProvider) {
|
|
85
96
|
logs.setGlobalLoggerProvider(this.loggerProvider);
|
|
86
97
|
}
|
|
98
|
+
if (this.tracerProvider) {
|
|
99
|
+
this.tracerProvider.register();
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Returns a tracer for manual spans. Requires {@link OpenTelemetryProviderOptions.tracesExporter}
|
|
105
|
+
* so that a {@link NodeTracerProvider} is registered.
|
|
106
|
+
*/
|
|
107
|
+
getTracer(name = "cline", version?: string): Tracer {
|
|
108
|
+
return trace.getTracer(name, version ?? this.options.serviceVersion);
|
|
87
109
|
}
|
|
88
110
|
|
|
89
111
|
createAdapter(
|
|
@@ -122,6 +144,7 @@ export class OpenTelemetryProvider {
|
|
|
122
144
|
await Promise.all([
|
|
123
145
|
this.meterProvider?.forceFlush?.(),
|
|
124
146
|
this.loggerProvider?.forceFlush?.(),
|
|
147
|
+
this.tracerProvider?.forceFlush?.(),
|
|
125
148
|
]);
|
|
126
149
|
}
|
|
127
150
|
|
|
@@ -129,10 +152,13 @@ export class OpenTelemetryProvider {
|
|
|
129
152
|
await Promise.all([
|
|
130
153
|
this.meterProvider?.shutdown?.(),
|
|
131
154
|
this.loggerProvider?.shutdown?.(),
|
|
155
|
+
this.tracerProvider?.shutdown?.(),
|
|
132
156
|
]);
|
|
133
157
|
}
|
|
134
158
|
|
|
135
|
-
private createMeterProvider(
|
|
159
|
+
private createMeterProvider(
|
|
160
|
+
resource: ReturnType<typeof resourceFromAttributes>,
|
|
161
|
+
): MeterProvider | null {
|
|
136
162
|
const exporters = normalizeExporters(this.options.metricsExporter);
|
|
137
163
|
if (exporters.length === 0) {
|
|
138
164
|
return null;
|
|
@@ -168,35 +194,71 @@ export class OpenTelemetryProvider {
|
|
|
168
194
|
});
|
|
169
195
|
}
|
|
170
196
|
|
|
171
|
-
private
|
|
172
|
-
|
|
197
|
+
private createTracerProvider(
|
|
198
|
+
resource: ReturnType<typeof resourceFromAttributes>,
|
|
199
|
+
): NodeTracerProvider | null {
|
|
200
|
+
const exporters = normalizeExporters(this.options.tracesExporter);
|
|
173
201
|
if (exporters.length === 0) {
|
|
174
202
|
return null;
|
|
175
203
|
}
|
|
176
204
|
|
|
177
|
-
const
|
|
205
|
+
const traceEndpoint =
|
|
206
|
+
this.options.otlpTracesEndpoint ?? this.options.otlpEndpoint;
|
|
207
|
+
const traceHeaders =
|
|
208
|
+
this.options.otlpTracesHeaders ?? this.options.otlpHeaders;
|
|
209
|
+
|
|
210
|
+
const processors: SpanProcessor[] = [];
|
|
178
211
|
for (const exporter of exporters) {
|
|
179
|
-
const
|
|
180
|
-
endpoint:
|
|
181
|
-
headers:
|
|
212
|
+
const processor = createSpanProcessor(exporter, {
|
|
213
|
+
endpoint: traceEndpoint,
|
|
214
|
+
headers: traceHeaders,
|
|
182
215
|
insecure: this.options.otlpInsecure ?? false,
|
|
183
216
|
protocol: "http/json",
|
|
184
217
|
});
|
|
185
|
-
if (
|
|
186
|
-
|
|
218
|
+
if (processor) {
|
|
219
|
+
processors.push(processor);
|
|
187
220
|
}
|
|
188
|
-
|
|
189
|
-
|
|
221
|
+
}
|
|
222
|
+
if (processors.length === 0) {
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
return new NodeTracerProvider({ resource, spanProcessors: processors });
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
private createLoggerProvider(
|
|
230
|
+
resource: ReturnType<typeof resourceFromAttributes>,
|
|
231
|
+
): LoggerProvider | null {
|
|
232
|
+
const exporters = normalizeExporters(this.options.logsExporter);
|
|
233
|
+
if (exporters.length === 0) {
|
|
234
|
+
return null;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const processors = exporters
|
|
238
|
+
.map((exporter) => {
|
|
239
|
+
const logExporter = createLogExporter(exporter, {
|
|
240
|
+
endpoint: this.options.otlpEndpoint,
|
|
241
|
+
headers: this.options.otlpHeaders,
|
|
242
|
+
insecure: this.options.otlpInsecure ?? false,
|
|
243
|
+
protocol: "http/json",
|
|
244
|
+
});
|
|
245
|
+
if (!logExporter) {
|
|
246
|
+
return null;
|
|
247
|
+
}
|
|
248
|
+
return new BatchLogRecordProcessor(logExporter, {
|
|
190
249
|
maxQueueSize: this.options.logMaxQueueSize ?? 2048,
|
|
191
250
|
maxExportBatchSize: this.options.logBatchSize ?? 512,
|
|
192
251
|
scheduledDelayMillis:
|
|
193
252
|
this.options.logBatchTimeoutMs ??
|
|
194
253
|
this.options.logBatchTimeout ??
|
|
195
254
|
5000,
|
|
196
|
-
})
|
|
197
|
-
)
|
|
255
|
+
});
|
|
256
|
+
})
|
|
257
|
+
.filter((p): p is BatchLogRecordProcessor => p !== null);
|
|
258
|
+
if (processors.length === 0) {
|
|
259
|
+
return null;
|
|
198
260
|
}
|
|
199
|
-
return
|
|
261
|
+
return new LoggerProvider({ resource, processors });
|
|
200
262
|
}
|
|
201
263
|
}
|
|
202
264
|
|
|
@@ -214,6 +276,9 @@ export function createOpenTelemetryTelemetryService(
|
|
|
214
276
|
metricsExporter: Array.isArray(options.metricsExporter)
|
|
215
277
|
? options.metricsExporter.join(",")
|
|
216
278
|
: options.metricsExporter,
|
|
279
|
+
tracesExporter: Array.isArray(options.tracesExporter)
|
|
280
|
+
? options.tracesExporter.join(",")
|
|
281
|
+
: options.tracesExporter,
|
|
217
282
|
otlpProtocol: options.otlpProtocol,
|
|
218
283
|
hasOtlpEndpoint: Boolean(options.otlpEndpoint),
|
|
219
284
|
serviceName: options.serviceName,
|
|
@@ -280,6 +345,31 @@ function createLogExporter(
|
|
|
280
345
|
});
|
|
281
346
|
}
|
|
282
347
|
|
|
348
|
+
function createSpanProcessor(
|
|
349
|
+
exporter: OpenTelemetryExporterKind,
|
|
350
|
+
options: {
|
|
351
|
+
endpoint?: string;
|
|
352
|
+
headers?: Record<string, string>;
|
|
353
|
+
insecure: boolean;
|
|
354
|
+
protocol: OpenTelemetryProtocol;
|
|
355
|
+
},
|
|
356
|
+
): SpanProcessor | null {
|
|
357
|
+
if (exporter === "console") {
|
|
358
|
+
return new SimpleSpanProcessor(new ConsoleSpanExporter());
|
|
359
|
+
}
|
|
360
|
+
if (!options.endpoint) {
|
|
361
|
+
return null;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
const endpoint = ensurePathSuffix(options.endpoint, "/v1/traces");
|
|
365
|
+
return new BatchSpanProcessor(
|
|
366
|
+
new OTLPTraceExporter({
|
|
367
|
+
url: endpoint,
|
|
368
|
+
headers: options.headers,
|
|
369
|
+
}),
|
|
370
|
+
);
|
|
371
|
+
}
|
|
372
|
+
|
|
283
373
|
function createMetricReader(
|
|
284
374
|
exporter: OpenTelemetryExporterKind,
|
|
285
375
|
options: {
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { TelemetryLoggerSink } from "./TelemetryLoggerSink";
|
|
3
|
+
|
|
4
|
+
describe("TelemetryLoggerSink", () => {
|
|
5
|
+
it("logs events and metrics through the provided logger", async () => {
|
|
6
|
+
const logger = {
|
|
7
|
+
debug: vi.fn(),
|
|
8
|
+
log: vi.fn(),
|
|
9
|
+
};
|
|
10
|
+
const sink = new TelemetryLoggerSink({ logger });
|
|
11
|
+
|
|
12
|
+
sink.emit("session.started", { sessionId: "s1" });
|
|
13
|
+
sink.emitRequired("user.opt_out", { reason: "manual" });
|
|
14
|
+
sink.recordCounter("cline.session.starts.total", 1, {
|
|
15
|
+
sessionId: "s1",
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
expect(logger.log).toHaveBeenCalledWith("telemetry.event", {
|
|
19
|
+
telemetrySink: "TelemetryLoggerSink",
|
|
20
|
+
event: "session.started",
|
|
21
|
+
properties: { sessionId: "s1" },
|
|
22
|
+
});
|
|
23
|
+
expect(logger.log).toHaveBeenCalledWith("telemetry.required_event", {
|
|
24
|
+
telemetrySink: "TelemetryLoggerSink",
|
|
25
|
+
severity: "warn",
|
|
26
|
+
event: "user.opt_out",
|
|
27
|
+
properties: { reason: "manual" },
|
|
28
|
+
});
|
|
29
|
+
expect(logger.debug).toHaveBeenCalledWith("telemetry.metric", {
|
|
30
|
+
telemetrySink: "TelemetryLoggerSink",
|
|
31
|
+
instrument: "counter",
|
|
32
|
+
name: "cline.session.starts.total",
|
|
33
|
+
value: 1,
|
|
34
|
+
attributes: { sessionId: "s1" },
|
|
35
|
+
description: undefined,
|
|
36
|
+
required: false,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
await sink.flush();
|
|
40
|
+
await sink.dispose();
|
|
41
|
+
});
|
|
42
|
+
});
|
|
@@ -4,20 +4,26 @@ import type {
|
|
|
4
4
|
TelemetryProperties,
|
|
5
5
|
} from "./ITelemetryAdapter";
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
/**
|
|
8
|
+
* {@link ITelemetryAdapter} implementation that forwards telemetry to a {@link BasicLogger}.
|
|
9
|
+
*
|
|
10
|
+
* This is intentionally named *Sink* (not "adapter") to distinguish it from host logging bridges
|
|
11
|
+
* such as the CLI Pino bundle: it consumes telemetry events and writes them to the injected logger.
|
|
12
|
+
*/
|
|
13
|
+
export interface TelemetryLoggerSinkOptions {
|
|
8
14
|
logger?: BasicLogger;
|
|
9
15
|
name?: string;
|
|
10
16
|
enabled?: boolean | (() => boolean);
|
|
11
17
|
}
|
|
12
18
|
|
|
13
|
-
export class
|
|
19
|
+
export class TelemetryLoggerSink implements ITelemetryAdapter {
|
|
14
20
|
readonly name: string;
|
|
15
21
|
|
|
16
22
|
private readonly logger?: BasicLogger;
|
|
17
23
|
private readonly enabled: boolean | (() => boolean);
|
|
18
24
|
|
|
19
|
-
constructor(options:
|
|
20
|
-
this.name = options.name ?? "
|
|
25
|
+
constructor(options: TelemetryLoggerSinkOptions = {}) {
|
|
26
|
+
this.name = options.name ?? "TelemetryLoggerSink";
|
|
21
27
|
this.logger = options.logger;
|
|
22
28
|
this.enabled = options.enabled ?? true;
|
|
23
29
|
}
|
|
@@ -26,16 +32,17 @@ export class LoggerTelemetryAdapter implements ITelemetryAdapter {
|
|
|
26
32
|
if (!this.isEnabled()) {
|
|
27
33
|
return;
|
|
28
34
|
}
|
|
29
|
-
this.logger?.
|
|
30
|
-
|
|
35
|
+
this.logger?.log("telemetry.event", {
|
|
36
|
+
telemetrySink: this.name,
|
|
31
37
|
event,
|
|
32
38
|
properties,
|
|
33
39
|
});
|
|
34
40
|
}
|
|
35
41
|
|
|
36
42
|
emitRequired(event: string, properties?: TelemetryProperties): void {
|
|
37
|
-
this.logger?.
|
|
38
|
-
|
|
43
|
+
this.logger?.log("telemetry.required_event", {
|
|
44
|
+
telemetrySink: this.name,
|
|
45
|
+
severity: "warn",
|
|
39
46
|
event,
|
|
40
47
|
properties,
|
|
41
48
|
});
|
|
@@ -51,8 +58,8 @@ export class LoggerTelemetryAdapter implements ITelemetryAdapter {
|
|
|
51
58
|
if (!required && !this.isEnabled()) {
|
|
52
59
|
return;
|
|
53
60
|
}
|
|
54
|
-
this.logger?.debug
|
|
55
|
-
|
|
61
|
+
this.logger?.debug("telemetry.metric", {
|
|
62
|
+
telemetrySink: this.name,
|
|
56
63
|
instrument: "counter",
|
|
57
64
|
name,
|
|
58
65
|
value,
|
|
@@ -72,8 +79,8 @@ export class LoggerTelemetryAdapter implements ITelemetryAdapter {
|
|
|
72
79
|
if (!required && !this.isEnabled()) {
|
|
73
80
|
return;
|
|
74
81
|
}
|
|
75
|
-
this.logger?.debug
|
|
76
|
-
|
|
82
|
+
this.logger?.debug("telemetry.metric", {
|
|
83
|
+
telemetrySink: this.name,
|
|
77
84
|
instrument: "histogram",
|
|
78
85
|
name,
|
|
79
86
|
value,
|
|
@@ -93,8 +100,8 @@ export class LoggerTelemetryAdapter implements ITelemetryAdapter {
|
|
|
93
100
|
if (!required && !this.isEnabled()) {
|
|
94
101
|
return;
|
|
95
102
|
}
|
|
96
|
-
this.logger?.debug
|
|
97
|
-
|
|
103
|
+
this.logger?.debug("telemetry.metric", {
|
|
104
|
+
telemetrySink: this.name,
|
|
98
105
|
instrument: "gauge",
|
|
99
106
|
name,
|
|
100
107
|
value,
|
|
@@ -53,8 +53,7 @@ describe("TelemetryService", () => {
|
|
|
53
53
|
it("mirrors telemetry events into the logger when provided", () => {
|
|
54
54
|
const logger: BasicLogger = {
|
|
55
55
|
debug: vi.fn(),
|
|
56
|
-
|
|
57
|
-
warn: vi.fn(),
|
|
56
|
+
log: vi.fn(),
|
|
58
57
|
error: vi.fn(),
|
|
59
58
|
};
|
|
60
59
|
const service = new TelemetryService({
|
|
@@ -75,10 +74,10 @@ describe("TelemetryService", () => {
|
|
|
75
74
|
sessionId: "session-1",
|
|
76
75
|
});
|
|
77
76
|
|
|
78
|
-
expect(logger.
|
|
77
|
+
expect(logger.log).toHaveBeenCalledWith(
|
|
79
78
|
"telemetry.event",
|
|
80
79
|
expect.objectContaining({
|
|
81
|
-
|
|
80
|
+
telemetrySink: "TelemetryLoggerSink",
|
|
82
81
|
event: "session.started",
|
|
83
82
|
properties: expect.objectContaining({
|
|
84
83
|
sessionId: "session-1",
|
|
@@ -87,10 +86,11 @@ describe("TelemetryService", () => {
|
|
|
87
86
|
}),
|
|
88
87
|
}),
|
|
89
88
|
);
|
|
90
|
-
expect(logger.
|
|
89
|
+
expect(logger.log).toHaveBeenCalledWith(
|
|
91
90
|
"telemetry.required_event",
|
|
92
91
|
expect.objectContaining({
|
|
93
|
-
|
|
92
|
+
telemetrySink: "TelemetryLoggerSink",
|
|
93
|
+
severity: "warn",
|
|
94
94
|
event: "user.opt_out",
|
|
95
95
|
properties: expect.objectContaining({
|
|
96
96
|
reason: "manual",
|
|
@@ -101,7 +101,7 @@ describe("TelemetryService", () => {
|
|
|
101
101
|
expect(logger.debug).toHaveBeenCalledWith(
|
|
102
102
|
"telemetry.metric",
|
|
103
103
|
expect.objectContaining({
|
|
104
|
-
|
|
104
|
+
telemetrySink: "TelemetryLoggerSink",
|
|
105
105
|
instrument: "counter",
|
|
106
106
|
name: "cline.session.starts.total",
|
|
107
107
|
}),
|
|
@@ -5,7 +5,7 @@ import type {
|
|
|
5
5
|
TelemetryProperties,
|
|
6
6
|
} from "@clinebot/shared";
|
|
7
7
|
import type { ITelemetryAdapter } from "./ITelemetryAdapter";
|
|
8
|
-
import {
|
|
8
|
+
import { TelemetryLoggerSink } from "./TelemetryLoggerSink";
|
|
9
9
|
|
|
10
10
|
export interface TelemetryServiceOptions {
|
|
11
11
|
adapters?: ITelemetryAdapter[];
|
|
@@ -24,9 +24,7 @@ export class TelemetryService implements ITelemetryService {
|
|
|
24
24
|
constructor(options: TelemetryServiceOptions = {}) {
|
|
25
25
|
this.adapters = [...(options.adapters ?? [])];
|
|
26
26
|
if (options.logger) {
|
|
27
|
-
this.adapters.push(
|
|
28
|
-
new LoggerTelemetryAdapter({ logger: options.logger }),
|
|
29
|
-
);
|
|
27
|
+
this.adapters.push(new TelemetryLoggerSink({ logger: options.logger }));
|
|
30
28
|
}
|
|
31
29
|
this.metadata = { ...(options.metadata ?? {}) };
|
|
32
30
|
this.distinctId = options.distinctId;
|
|
@@ -187,6 +187,82 @@ describe("default ask_question tool", () => {
|
|
|
187
187
|
});
|
|
188
188
|
});
|
|
189
189
|
|
|
190
|
+
describe("default submit_and_exit tool", () => {
|
|
191
|
+
it("is excluded by default even when executor is provided", () => {
|
|
192
|
+
const tools = createDefaultTools({
|
|
193
|
+
executors: {
|
|
194
|
+
submit: async () => "ok",
|
|
195
|
+
},
|
|
196
|
+
});
|
|
197
|
+
expect(tools.map((tool) => tool.name)).not.toContain("submit_and_exit");
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
it("is included only when enabled with a submit executor", () => {
|
|
201
|
+
const toolsWithoutExecutor = createDefaultTools({
|
|
202
|
+
executors: {},
|
|
203
|
+
enableSubmitAndExit: true,
|
|
204
|
+
});
|
|
205
|
+
expect(toolsWithoutExecutor.map((tool) => tool.name)).not.toContain(
|
|
206
|
+
"submit_and_exit",
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
const toolsWithExecutor = createDefaultTools({
|
|
210
|
+
executors: {
|
|
211
|
+
submit: async () => "ok",
|
|
212
|
+
},
|
|
213
|
+
enableSubmitAndExit: true,
|
|
214
|
+
});
|
|
215
|
+
expect(toolsWithExecutor.map((tool) => tool.name)).toContain(
|
|
216
|
+
"submit_and_exit",
|
|
217
|
+
);
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
it("validates and executes submit_and_exit input", async () => {
|
|
221
|
+
const execute = vi.fn(async () => "submitted");
|
|
222
|
+
const tools = createDefaultTools({
|
|
223
|
+
executors: {
|
|
224
|
+
submit: execute,
|
|
225
|
+
},
|
|
226
|
+
enableReadFiles: false,
|
|
227
|
+
enableSearch: false,
|
|
228
|
+
enableBash: false,
|
|
229
|
+
enableWebFetch: false,
|
|
230
|
+
enableEditor: false,
|
|
231
|
+
enableSkills: false,
|
|
232
|
+
enableAskQuestion: false,
|
|
233
|
+
enableSubmitAndExit: true,
|
|
234
|
+
});
|
|
235
|
+
const submitTool = tools.find((tool) => tool.name === "submit_and_exit");
|
|
236
|
+
expect(submitTool).toBeDefined();
|
|
237
|
+
if (!submitTool) {
|
|
238
|
+
throw new Error("Expected submit_and_exit tool to be defined.");
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const result = await submitTool.execute(
|
|
242
|
+
{
|
|
243
|
+
summary: "Done and verified with the requested checks.",
|
|
244
|
+
verified: true,
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
agentId: "agent-1",
|
|
248
|
+
conversationId: "conv-1",
|
|
249
|
+
iteration: 1,
|
|
250
|
+
},
|
|
251
|
+
);
|
|
252
|
+
|
|
253
|
+
expect(result).toBe("submitted");
|
|
254
|
+
expect(execute).toHaveBeenCalledWith(
|
|
255
|
+
"Done and verified with the requested checks.",
|
|
256
|
+
true,
|
|
257
|
+
expect.objectContaining({
|
|
258
|
+
agentId: "agent-1",
|
|
259
|
+
conversationId: "conv-1",
|
|
260
|
+
iteration: 1,
|
|
261
|
+
}),
|
|
262
|
+
);
|
|
263
|
+
});
|
|
264
|
+
});
|
|
265
|
+
|
|
190
266
|
describe("default apply_patch tool", () => {
|
|
191
267
|
it("is included only when enabled with an applyPatch executor", () => {
|
|
192
268
|
const toolsWithoutExecutor = createDefaultTools({
|
package/src/tools/definitions.ts
CHANGED
|
@@ -4,8 +4,12 @@
|
|
|
4
4
|
* Factory functions for creating the default tools.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import {
|
|
8
|
-
|
|
7
|
+
import {
|
|
8
|
+
createTool,
|
|
9
|
+
type Tool,
|
|
10
|
+
validateWithZod,
|
|
11
|
+
zodToJsonSchema,
|
|
12
|
+
} from "@clinebot/shared";
|
|
9
13
|
import {
|
|
10
14
|
formatError,
|
|
11
15
|
formatReadFileQuery,
|
|
@@ -37,6 +41,8 @@ import {
|
|
|
37
41
|
SkillsInputSchema,
|
|
38
42
|
type StructuredCommandInput,
|
|
39
43
|
StructuredCommandsInputUnionSchema,
|
|
44
|
+
type SubmitInput,
|
|
45
|
+
SubmitInputSchema,
|
|
40
46
|
} from "./schemas";
|
|
41
47
|
import type {
|
|
42
48
|
ApplyPatchExecutor,
|
|
@@ -49,6 +55,7 @@ import type {
|
|
|
49
55
|
SearchExecutor,
|
|
50
56
|
SkillsExecutorWithMetadata,
|
|
51
57
|
ToolOperationResult,
|
|
58
|
+
VerifySubmitExecutor,
|
|
52
59
|
WebFetchExecutor,
|
|
53
60
|
} from "./types";
|
|
54
61
|
|
|
@@ -603,6 +610,34 @@ export function createAskQuestionTool(
|
|
|
603
610
|
});
|
|
604
611
|
}
|
|
605
612
|
|
|
613
|
+
export function createSubmitAndExitTool(
|
|
614
|
+
executor: VerifySubmitExecutor,
|
|
615
|
+
config: Pick<DefaultToolsConfig, "submitTimeoutMs"> = {},
|
|
616
|
+
): Tool<SubmitInput, string> {
|
|
617
|
+
const timeoutMs = config.submitTimeoutMs ?? 15000;
|
|
618
|
+
|
|
619
|
+
return createTool<SubmitInput, string>({
|
|
620
|
+
name: "submit_and_exit",
|
|
621
|
+
description:
|
|
622
|
+
"Submit the final answer and exit the conversation. " +
|
|
623
|
+
"For example, submit a summary of the investigation and confirm the issue is resolved. " +
|
|
624
|
+
"You should only submit once all necessary steps are completed. " +
|
|
625
|
+
"Provide a summary of the investigation and confirm the issue is resolved.",
|
|
626
|
+
inputSchema: zodToJsonSchema(SubmitInputSchema),
|
|
627
|
+
timeoutMs,
|
|
628
|
+
retryable: false,
|
|
629
|
+
maxRetries: 0,
|
|
630
|
+
execute: async (input, context) => {
|
|
631
|
+
const validatedInput = validateWithZod(SubmitInputSchema, input);
|
|
632
|
+
return withTimeout(
|
|
633
|
+
executor(validatedInput.summary, validatedInput.verified, context),
|
|
634
|
+
timeoutMs,
|
|
635
|
+
`submit_and_exit timed out after ${timeoutMs}ms`,
|
|
636
|
+
);
|
|
637
|
+
},
|
|
638
|
+
});
|
|
639
|
+
}
|
|
640
|
+
|
|
606
641
|
// =============================================================================
|
|
607
642
|
// Default Tools Factory
|
|
608
643
|
// =============================================================================
|
|
@@ -657,6 +692,7 @@ export function createDefaultTools(options: CreateDefaultToolsOptions): Tool[] {
|
|
|
657
692
|
enableEditor = true,
|
|
658
693
|
enableSkills = true,
|
|
659
694
|
enableAskQuestion = true,
|
|
695
|
+
enableSubmitAndExit = false,
|
|
660
696
|
...config
|
|
661
697
|
} = options;
|
|
662
698
|
|
|
@@ -703,6 +739,9 @@ export function createDefaultTools(options: CreateDefaultToolsOptions): Tool[] {
|
|
|
703
739
|
// Add ask_question tool if enabled and executor provided
|
|
704
740
|
if (enableAskQuestion && executors.askQuestion) {
|
|
705
741
|
tools.push(createAskQuestionTool(executors.askQuestion, config));
|
|
742
|
+
} else if (enableSubmitAndExit && executors.submit) {
|
|
743
|
+
// Add submit_and_exit tool if enabled and executor provided
|
|
744
|
+
tools.push(createSubmitAndExitTool(executors.submit, config));
|
|
706
745
|
}
|
|
707
746
|
|
|
708
747
|
return tools;
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
import * as fs from "node:fs/promises";
|
|
8
8
|
import * as path from "node:path";
|
|
9
|
-
import type { ToolContext } from "@clinebot/
|
|
9
|
+
import type { ToolContext } from "@clinebot/shared";
|
|
10
10
|
import type { ApplyPatchInput } from "../schemas";
|
|
11
11
|
import type { ApplyPatchExecutor } from "../types";
|
|
12
12
|
import {
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
import * as fs from "node:fs/promises";
|
|
8
8
|
import * as path from "node:path";
|
|
9
|
-
import type { ToolContext } from "@clinebot/
|
|
9
|
+
import type { ToolContext } from "@clinebot/shared";
|
|
10
10
|
import type { EditFileInput } from "../schemas";
|
|
11
11
|
import type { EditorExecutor } from "../types";
|
|
12
12
|
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
import * as fs from "node:fs/promises";
|
|
8
8
|
import * as path from "node:path";
|
|
9
|
-
import type { ToolContext } from "@clinebot/
|
|
9
|
+
import type { ToolContext } from "@clinebot/shared";
|
|
10
10
|
import type { ReadFileRequest } from "../schemas";
|
|
11
11
|
import type { FileReadExecutor } from "../types";
|
|
12
12
|
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
import * as fs from "node:fs/promises";
|
|
8
8
|
import * as path from "node:path";
|
|
9
|
-
import type { ToolContext } from "@clinebot/
|
|
9
|
+
import type { ToolContext } from "@clinebot/shared";
|
|
10
10
|
import { getFileIndex } from "../../input";
|
|
11
11
|
import type { SearchExecutor } from "../types";
|
|
12
12
|
|