authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-03-05 17:52:05-08:00
committergravatar for jmarminge@gmail.comJulius Marminge <jmarminge@gmail.com> 2026-03-05 23:40:49-08:00
logfcb1a50ee42a051ed1c0605f688cb6c94f043838
tree3f0593d72ba31030228da26d7d066cb20dd98fa4
parentec3778bbf4a5d8726cff22bddfcba82cd1c6ebde

adjust


5 files changed, 19 insertions(+), 17 deletions(-)

apps/server/src/index.ts+2-2
...@@ -10,7 +10,7 @@ import { version } from "../package.json" with { type: "json" };...@@ -10,7 +10,7 @@ import { version } from "../package.json" with { type: "json" };
10import { ServerLive } from "./wsServer";10import { ServerLive } from "./wsServer";
11import { NetService } from "@t3tools/shared/Net";11import { NetService } from "@t3tools/shared/Net";
12import { AnalyticsServiceLayerLive } from "./telemetry/Layers/AnalyticsService";12import { AnalyticsServiceLayerLive } from "./telemetry/Layers/AnalyticsService";
13import * as NodeHttpClient from "@effect/platform-node/NodeHttpClient";13import { FetchHttpClient } from "effect/unstable/http";
1414
15const RuntimeLayer = Layer.empty.pipe(15const RuntimeLayer = Layer.empty.pipe(
16 Layer.provideMerge(CliConfig.layer),16 Layer.provideMerge(CliConfig.layer),
...@@ -19,7 +19,7 @@ const RuntimeLayer = Layer.empty.pipe(...@@ -19,7 +19,7 @@ const RuntimeLayer = Layer.empty.pipe(
19 Layer.provideMerge(OpenLive),19 Layer.provideMerge(OpenLive),
20 Layer.provideMerge(NetService.layer),20 Layer.provideMerge(NetService.layer),
21 Layer.provideMerge(NodeServices.layer),21 Layer.provideMerge(NodeServices.layer),
22 Layer.provideMerge(NodeHttpClient.layerUndici),22 Layer.provideMerge(FetchHttpClient.layer),
23);23);
2424
25Command.run(t3Cli, { version }).pipe(Effect.provide(RuntimeLayer), NodeRuntime.runMain);25Command.run(t3Cli, { version }).pipe(Effect.provide(RuntimeLayer), NodeRuntime.runMain);
apps/server/src/provider/Layers/ProviderService.ts+2-8
...@@ -276,8 +276,6 @@ const makeProviderService = (options?: ProviderServiceLiveOptions) =>...@@ -276,8 +276,6 @@ const makeProviderService = (options?: ProviderServiceLiveOptions) =>
276 yield* upsertSessionBinding(session, threadId);276 yield* upsertSessionBinding(session, threadId);
277 yield* analytics.record("provider.session.started", {277 yield* analytics.record("provider.session.started", {
278 provider: session.provider,278 provider: session.provider,
279 hasResumeCursor: session.resumeCursor !== undefined,
280 hasCwd: typeof input.cwd === "string" && input.cwd.trim().length > 0,
281 approvalPolicy: input.approvalPolicy,279 approvalPolicy: input.approvalPolicy,
282 sandboxMode: input.sandboxMode,280 sandboxMode: input.sandboxMode,
283 });281 });
...@@ -322,8 +320,8 @@ const makeProviderService = (options?: ProviderServiceLiveOptions) =>...@@ -322,8 +320,8 @@ const makeProviderService = (options?: ProviderServiceLiveOptions) =>
322 });320 });
323 yield* analytics.record("provider.turn.sent", {321 yield* analytics.record("provider.turn.sent", {
324 provider: routed.adapter.provider,322 provider: routed.adapter.provider,
325 attachmentCount: input.attachments.length,323 model: input.model,
326 hasInput: typeof input.input === "string" && input.input.trim().length > 0,324 effort: input.effort,
327 });325 });
328 return turn;326 return turn;
329 });327 });
...@@ -343,7 +341,6 @@ const makeProviderService = (options?: ProviderServiceLiveOptions) =>...@@ -343,7 +341,6 @@ const makeProviderService = (options?: ProviderServiceLiveOptions) =>
343 yield* routed.adapter.interruptTurn(routed.threadId, input.turnId);341 yield* routed.adapter.interruptTurn(routed.threadId, input.turnId);
344 yield* analytics.record("provider.turn.interrupted", {342 yield* analytics.record("provider.turn.interrupted", {
345 provider: routed.adapter.provider,343 provider: routed.adapter.provider,
346 hasTurnId: input.turnId !== undefined,
347 });344 });
348 });345 });
349346
...@@ -379,8 +376,6 @@ const makeProviderService = (options?: ProviderServiceLiveOptions) =>...@@ -379,8 +376,6 @@ const makeProviderService = (options?: ProviderServiceLiveOptions) =>
379 allowRecovery: true,376 allowRecovery: true,
380 });377 });
381 yield* routed.adapter.respondToUserInput(routed.threadId, input.requestId, input.answers);378 yield* routed.adapter.respondToUserInput(routed.threadId, input.requestId, input.answers);
382 yield* analytics.record("provider.user_input.responded", {
383 provider: routed.adapter.provider,
384 });379 });
385 });380 });
386381
...@@ -402,7 +397,6 @@ const makeProviderService = (options?: ProviderServiceLiveOptions) =>...@@ -402,7 +397,6 @@ const makeProviderService = (options?: ProviderServiceLiveOptions) =>
402 yield* directory.remove(input.threadId);397 yield* directory.remove(input.threadId);
403 yield* analytics.record("provider.session.stopped", {398 yield* analytics.record("provider.session.stopped", {
404 provider: routed.adapter.provider,399 provider: routed.adapter.provider,
405 wasActive: routed.isActive,
406 });400 });
407 });401 });
408402
apps/server/src/telemetry/Layers/AnalyticsService.ts+5-1
...@@ -126,7 +126,11 @@ const makeAnalyticsService = Effect.gen(function* () {...@@ -126,7 +126,11 @@ const makeAnalyticsService = Effect.gen(function* () {
126 }126 }
127 });127 });
128128
129 yield* Effect.forever(flush, { disableYield: true }).pipe(Effect.forkDetach);129 yield* Effect.forever(Effect.sleep(1000).pipe(Effect.flatMap(() => flush)), {
130 disableYield: true,
131 }).pipe(Effect.forkDetach);
132
133 yield* Effect.addFinalizer(() => flush);
130134
131 return {135 return {
132 record,136 record,
apps/server/src/telemetry/Services/AnalyticsService.ts+7-2
...@@ -6,7 +6,7 @@...@@ -6,7 +6,7 @@
6 *6 *
7 * @module AnalyticsService7 * @module AnalyticsService
8 */8 */
9import { Effect, ServiceMap } from "effect";9import { Effect, Layer, ServiceMap } from "effect";
1010
11export interface AnalyticsServiceShape {11export interface AnalyticsServiceShape {
12 /**12 /**
...@@ -25,4 +25,9 @@ export interface AnalyticsServiceShape {...@@ -25,4 +25,9 @@ export interface AnalyticsServiceShape {
2525
26export class AnalyticsService extends ServiceMap.Service<AnalyticsService, AnalyticsServiceShape>()(26export class AnalyticsService extends ServiceMap.Service<AnalyticsService, AnalyticsServiceShape>()(
27 "t3/telemetry/Services/AnalyticsService",27 "t3/telemetry/Services/AnalyticsService",
28) {}28) {
29 static readonly layerTest = Layer.succeed(AnalyticsService, {
30 record: () => Effect.void,
31 flush: Effect.void,
32 });
33}
apps/server/src/wsServer.test.ts+3-4
...@@ -50,8 +50,7 @@ import type { GitCoreShape } from "./git/Services/GitCore.ts";...@@ -50,8 +50,7 @@ import type { GitCoreShape } from "./git/Services/GitCore.ts";
50import { GitCore } from "./git/Services/GitCore.ts";50import { GitCore } from "./git/Services/GitCore.ts";
51import { GitCommandError, GitManagerError } from "./git/Errors.ts";51import { GitCommandError, GitManagerError } from "./git/Errors.ts";
52import { MigrationError } from "@effect/sql-sqlite-bun/SqliteMigrator";52import { MigrationError } from "@effect/sql-sqlite-bun/SqliteMigrator";
53import { AnalyticsServiceLayerLive } from "./telemetry/Layers/AnalyticsService.ts";53import { AnalyticsService } from "./telemetry/Services/AnalyticsService.ts";
54import * as NodeHttpClient from "@effect/platform-node/NodeHttpClient";
5554
56interface PendingMessages {55interface PendingMessages {
57 queue: unknown[];56 queue: unknown[];
...@@ -436,6 +435,7 @@ describe("WebSocket Server", () => {...@@ -436,6 +435,7 @@ describe("WebSocket Server", () => {
436 ? Layer.succeed(TerminalManager, options.terminalManager)435 ? Layer.succeed(TerminalManager, options.terminalManager)
437 : Layer.empty,436 : Layer.empty,
438 );437 );
438
439 const runtimeLayer = Layer.merge(439 const runtimeLayer = Layer.merge(
440 Layer.merge(440 Layer.merge(
441 makeServerRuntimeServicesLayer().pipe(Layer.provide(infrastructureLayer)),441 makeServerRuntimeServicesLayer().pipe(Layer.provide(infrastructureLayer)),
...@@ -448,9 +448,8 @@ describe("WebSocket Server", () => {...@@ -448,9 +448,8 @@ describe("WebSocket Server", () => {
448 Layer.provideMerge(providerHealthLayer),448 Layer.provideMerge(providerHealthLayer),
449 Layer.provideMerge(openLayer),449 Layer.provideMerge(openLayer),
450 Layer.provideMerge(serverConfigLayer),450 Layer.provideMerge(serverConfigLayer),
451 Layer.provideMerge(AnalyticsServiceLayerLive),451 Layer.provideMerge(AnalyticsService.layerTest),
452 Layer.provideMerge(NodeServices.layer),452 Layer.provideMerge(NodeServices.layer),
453 Layer.provideMerge(NodeHttpClient.layerUndici),
454 );453 );
455 const runtimeServices = await Effect.runPromise(454 const runtimeServices = await Effect.runPromise(
456 Layer.build(dependenciesLayer).pipe(Scope.provide(scope)),455 Layer.build(dependenciesLayer).pipe(Scope.provide(scope)),