@codemation/host 0.2.5 → 0.3.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.
Files changed (123) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/dist/{AppConfigFactory-CqKWXqOm.js → AppConfigFactory-BPp02HMv.js} +82 -5
  3. package/dist/{AppConfigFactory-CqKWXqOm.js.map → AppConfigFactory-BPp02HMv.js.map} +1 -1
  4. package/dist/{AppConfigFactory-CK28UPK0.d.ts → AppConfigFactory-Dq7ttwQ_.d.ts} +6001 -144
  5. package/dist/{AppContainerFactory-CcSGFNLW.js → AppContainerFactory-DL_qZ80U.js} +2665 -264
  6. package/dist/AppContainerFactory-DL_qZ80U.js.map +1 -0
  7. package/dist/{CodemationAppContext-KqDoeHqN.d.ts → CodemationAppContext-P7P-xZhQ.d.ts} +2 -2
  8. package/dist/{CodemationAuthoring.types-BP6Inucu.d.ts → CodemationAuthoring.types-OMYu7vKP.d.ts} +3 -3
  9. package/dist/{CodemationConfigNormalizer-DIAE0VHw.d.ts → CodemationConfigNormalizer-BCtBrJDe.d.ts} +2 -2
  10. package/dist/{CodemationConsumerConfigLoader-nj9kTmfJ.d.ts → CodemationConsumerConfigLoader-evvw4b_a.d.ts} +2 -2
  11. package/dist/CodemationPluginListMerger-PSTtEQjC.d.ts +674 -0
  12. package/dist/{CredentialServices-BFQD_VN1.d.ts → CredentialServices-0Hk8RFY1.d.ts} +3 -3
  13. package/dist/{CredentialServices-BPKUF8Xs.js → CredentialServices-BNBMFOPt.js} +6 -1
  14. package/dist/CredentialServices-BNBMFOPt.js.map +1 -0
  15. package/dist/{PublicFrontendBootstrapFactory-DTA1iDo0.d.ts → PublicFrontendBootstrapFactory-D0_ds7nS.d.ts} +2 -2
  16. package/dist/authoring.d.ts +3 -3
  17. package/dist/consumer.d.ts +4 -4
  18. package/dist/credentials.d.ts +3 -3
  19. package/dist/credentials.js +1 -1
  20. package/dist/devServerSidecar.d.ts +1 -1
  21. package/dist/{index-Dd6BrWyH.d.ts → index-CeS2saCe.d.ts} +105 -2
  22. package/dist/index.d.ts +12 -11
  23. package/dist/index.js +5 -5
  24. package/dist/nextServer.d.ts +8 -58
  25. package/dist/nextServer.js +6 -100
  26. package/dist/{persistenceServer-DKbFDxoS.js → persistenceServer-CA0_q0D7.js} +2 -2
  27. package/dist/{persistenceServer-DKbFDxoS.js.map → persistenceServer-CA0_q0D7.js.map} +1 -1
  28. package/dist/{persistenceServer-Y-u7lV7f.d.ts → persistenceServer-CJeu1STC.d.ts} +2 -2
  29. package/dist/persistenceServer.d.ts +5 -5
  30. package/dist/persistenceServer.js +2 -2
  31. package/dist/{server-axppTMgo.d.ts → server-Clvg5x1w.d.ts} +11 -5
  32. package/dist/{server-CFpgKuVE.js → server-DteBORJX.js} +4 -4
  33. package/dist/{server-CFpgKuVE.js.map → server-DteBORJX.js.map} +1 -1
  34. package/dist/server.d.ts +8 -8
  35. package/dist/server.js +5 -5
  36. package/package.json +6 -5
  37. package/prisma/migrations/20260414120000_telemetry_foundation/migration.sql +112 -0
  38. package/prisma/migrations/20260414153000_telemetry_retention_metrics_refactor/migration.sql +239 -0
  39. package/prisma/migrations.sqlite/20260414120000_telemetry_foundation/migration.sql +103 -0
  40. package/prisma/migrations.sqlite/20260414153000_telemetry_retention_metrics_refactor/migration.sql +540 -0
  41. package/prisma/schema.postgresql.prisma +100 -1
  42. package/prisma/schema.sqlite.prisma +100 -1
  43. package/scripts/generate-prisma-clients.mjs +89 -1
  44. package/src/application/contracts/TelemetryDashboardContracts.ts +113 -0
  45. package/src/application/contracts/TelemetryRunTraceContracts.ts +13 -0
  46. package/src/application/cost/FrameworkCostCatalogEntries.ts +126 -0
  47. package/src/application/queries/GetTelemetryDashboardDimensionsQuery.ts +11 -0
  48. package/src/application/queries/GetTelemetryDashboardDimensionsQueryHandler.ts +20 -0
  49. package/src/application/queries/GetTelemetryDashboardRunsQuery.ts +11 -0
  50. package/src/application/queries/GetTelemetryDashboardRunsQueryHandler.ts +20 -0
  51. package/src/application/queries/GetTelemetryDashboardSummaryQuery.ts +11 -0
  52. package/src/application/queries/GetTelemetryDashboardSummaryQueryHandler.ts +29 -0
  53. package/src/application/queries/GetTelemetryDashboardTimeseriesQuery.ts +11 -0
  54. package/src/application/queries/GetTelemetryDashboardTimeseriesQueryHandler.ts +36 -0
  55. package/src/application/queries/GetTelemetryRunTraceQuery.ts +8 -0
  56. package/src/application/queries/GetTelemetryRunTraceQueryHandler.ts +20 -0
  57. package/src/application/queries/WorkflowQueryHandlers.ts +5 -0
  58. package/src/application/runs/WorkflowRunRetentionPruneScheduler.ts +71 -26
  59. package/src/application/telemetry/CompositeTelemetryExporter.ts +13 -0
  60. package/src/application/telemetry/LazyExecutionTelemetryFactory.ts +21 -0
  61. package/src/application/telemetry/NoOpTelemetryExporter.ts +7 -0
  62. package/src/application/telemetry/OtelExecutionTelemetry.types.ts +41 -0
  63. package/src/application/telemetry/OtelExecutionTelemetryFactory.ts +56 -0
  64. package/src/application/telemetry/OtelIdentityFactory.ts +41 -0
  65. package/src/application/telemetry/RunEventBusTelemetryReporter.ts +188 -0
  66. package/src/application/telemetry/StoredExecutionTelemetry.ts +56 -0
  67. package/src/application/telemetry/StoredNodeExecutionTelemetry.ts +35 -0
  68. package/src/application/telemetry/StoredTelemetrySpanScope.ts +188 -0
  69. package/src/application/telemetry/TelemetryEnricherChain.ts +85 -0
  70. package/src/application/telemetry/TelemetryPrivacyPolicy.ts +19 -0
  71. package/src/application/telemetry/TelemetryQueryService.ts +815 -0
  72. package/src/application/telemetry/TelemetryRetentionTimestampFactory.ts +40 -0
  73. package/src/applicationTokens.ts +18 -0
  74. package/src/bootstrap/AppContainerFactory.ts +183 -64
  75. package/src/bootstrap/AppContainerLifecycle.ts +8 -0
  76. package/src/bootstrap/CodemationContainerRegistrationRegistrar.ts +1 -3
  77. package/src/bootstrap/runtime/FrontendRuntime.ts +8 -0
  78. package/src/bootstrap/runtime/WorkerRuntime.ts +8 -0
  79. package/src/domain/runs/WorkflowRunRepository.ts +3 -1
  80. package/src/domain/telemetry/TelemetryContracts.ts +197 -0
  81. package/src/infrastructure/config/CodemationPluginRegistrar.ts +2 -6
  82. package/src/infrastructure/di/HandlesDomainEventRegistry.ts +5 -7
  83. package/src/infrastructure/persistence/InMemoryRunTraceContextRepository.ts +56 -0
  84. package/src/infrastructure/persistence/InMemoryTelemetryArtifactStore.ts +56 -0
  85. package/src/infrastructure/persistence/InMemoryTelemetryMetricPointStore.ts +97 -0
  86. package/src/infrastructure/persistence/InMemoryTelemetrySpanStore.ts +113 -0
  87. package/src/infrastructure/persistence/InMemoryWorkflowRunRepository.ts +4 -2
  88. package/src/infrastructure/persistence/PrismaRunTraceContextRepository.ts +92 -0
  89. package/src/infrastructure/persistence/PrismaTelemetryArtifactStore.ts +125 -0
  90. package/src/infrastructure/persistence/PrismaTelemetryMetricPointStore.ts +134 -0
  91. package/src/infrastructure/persistence/PrismaTelemetrySpanStore.ts +166 -0
  92. package/src/infrastructure/persistence/PrismaWorkflowRunRepository.ts +20 -7
  93. package/src/infrastructure/persistence/generated/prisma-postgresql-client/edge.js +85 -4
  94. package/src/infrastructure/persistence/generated/prisma-postgresql-client/index-browser.js +81 -0
  95. package/src/infrastructure/persistence/generated/prisma-postgresql-client/index.d.ts +6488 -102
  96. package/src/infrastructure/persistence/generated/prisma-postgresql-client/index.js +85 -4
  97. package/src/infrastructure/persistence/generated/prisma-postgresql-client/package.json +1 -1
  98. package/src/infrastructure/persistence/generated/prisma-postgresql-client/schema.prisma +100 -0
  99. package/src/infrastructure/persistence/generated/prisma-sqlite-client/edge.js +85 -4
  100. package/src/infrastructure/persistence/generated/prisma-sqlite-client/index-browser.js +81 -0
  101. package/src/infrastructure/persistence/generated/prisma-sqlite-client/index.d.ts +6476 -98
  102. package/src/infrastructure/persistence/generated/prisma-sqlite-client/index.js +85 -4
  103. package/src/infrastructure/persistence/generated/prisma-sqlite-client/package.json +1 -1
  104. package/src/infrastructure/persistence/generated/prisma-sqlite-client/schema.prisma +100 -0
  105. package/src/presentation/http/ApiPaths.ts +22 -0
  106. package/src/presentation/http/hono/registrars/AuthHonoApiRouteRegistrar.ts +1 -3
  107. package/src/presentation/http/hono/registrars/BinaryHonoApiRouteRegistrar.ts +1 -3
  108. package/src/presentation/http/hono/registrars/BootstrapHonoApiRouteRegistrar.ts +1 -3
  109. package/src/presentation/http/hono/registrars/CredentialHonoApiRouteRegistrar.ts +1 -3
  110. package/src/presentation/http/hono/registrars/DevHonoApiRouteRegistrar.ts +1 -3
  111. package/src/presentation/http/hono/registrars/OAuth2HonoApiRouteRegistrar.ts +1 -3
  112. package/src/presentation/http/hono/registrars/RunHonoApiRouteRegistrar.ts +1 -3
  113. package/src/presentation/http/hono/registrars/TelemetryHonoApiRouteRegistrar.ts +17 -0
  114. package/src/presentation/http/hono/registrars/UserHonoApiRouteRegistrar.ts +1 -3
  115. package/src/presentation/http/hono/registrars/WebhookHonoApiRouteRegistrar.ts +1 -3
  116. package/src/presentation/http/hono/registrars/WhitelabelHonoApiRouteRegistrar.ts +1 -3
  117. package/src/presentation/http/hono/registrars/WorkflowHonoApiRouteRegistrar.ts +1 -3
  118. package/src/presentation/http/routeHandlers/TelemetryDashboardRequestError.ts +1 -0
  119. package/src/presentation/http/routeHandlers/TelemetryHttpRouteHandler.ts +181 -0
  120. package/dist/AppContainerFactory-CcSGFNLW.js.map +0 -1
  121. package/dist/CodemationPluginListMerger-QvUa2SIt.d.ts +0 -357
  122. package/dist/CredentialServices-BPKUF8Xs.js.map +0 -1
  123. package/dist/nextServer.js.map +0 -1
@@ -0,0 +1,188 @@
1
+ import type {
2
+ TelemetryArtifactAttachment,
3
+ TelemetryArtifactReference,
4
+ TelemetryAttributes,
5
+ TelemetryMetricRecord,
6
+ TelemetrySpanEnd,
7
+ TelemetrySpanEventRecord,
8
+ TelemetrySpanScope,
9
+ } from "@codemation/core";
10
+ import { NoOpTelemetryArtifactReference } from "@codemation/core";
11
+ import type { TelemetrySpanUpsert } from "../../domain/telemetry/TelemetryContracts";
12
+ import type { StoredSpanScopeArgs } from "./OtelExecutionTelemetry.types";
13
+
14
+ export class StoredTelemetrySpanScope implements TelemetrySpanScope {
15
+ readonly traceId: string;
16
+ readonly spanId: string;
17
+
18
+ protected readonly deps: StoredSpanScopeArgs;
19
+ protected readonly nodeId: string | undefined;
20
+ protected readonly activationId: string | undefined;
21
+ private readonly parentSpanId: string | undefined;
22
+ private readonly spanName: string;
23
+ private readonly spanKind: "internal" | "client";
24
+ private readonly initialAttributes: TelemetryAttributes | undefined;
25
+ private readonly initialStartTime: Date | undefined;
26
+ private readonly connectionInvocationId: string | undefined;
27
+ private readonly modelName: string | undefined;
28
+
29
+ constructor(args: StoredSpanScopeArgs) {
30
+ this.deps = args;
31
+ this.traceId = args.traceId;
32
+ this.spanId = args.spanId;
33
+ this.parentSpanId = args.parentSpanId;
34
+ this.nodeId = args.nodeId;
35
+ this.activationId = args.activationId;
36
+ this.spanName = args.spanName;
37
+ this.spanKind = args.spanKind;
38
+ this.initialAttributes = args.initialAttributes;
39
+ this.initialStartTime = args.initialStartTime;
40
+ this.connectionInvocationId = args.connectionInvocationId;
41
+ this.modelName = args.modelName;
42
+ }
43
+
44
+ async addSpanEvent(args: TelemetrySpanEventRecord): Promise<void> {
45
+ await this.upsert({
46
+ events: [args],
47
+ });
48
+ }
49
+
50
+ async recordMetric(args: TelemetryMetricRecord): Promise<void> {
51
+ const enrichment = await this.resolveEnrichment();
52
+ const observedAt = new Date();
53
+ await this.deps.telemetryMetricPointStore.save({
54
+ traceId: this.traceId,
55
+ spanId: this.spanId,
56
+ runId: this.deps.runId,
57
+ workflowId: this.deps.workflowId,
58
+ nodeId: this.nodeId,
59
+ activationId: this.activationId,
60
+ name: args.name,
61
+ value: args.value,
62
+ unit: args.unit,
63
+ attributes: args.attributes,
64
+ observedAt: observedAt.toISOString(),
65
+ workflowFolder: enrichment.workflowFolder,
66
+ nodeType: enrichment.nodeType,
67
+ nodeRole: enrichment.nodeRole,
68
+ modelName: this.modelName,
69
+ retentionExpiresAt: this.deps.telemetryRetentionTimestampFactory.createMetricExpiry(
70
+ this.deps.policySnapshot,
71
+ observedAt,
72
+ ),
73
+ });
74
+ await this.touchTraceContextExpiry(
75
+ this.deps.telemetryRetentionTimestampFactory.createTraceContextExpiry(this.deps.policySnapshot, observedAt),
76
+ );
77
+ }
78
+
79
+ async attachArtifact(args: TelemetryArtifactAttachment): Promise<TelemetryArtifactReference> {
80
+ if (!this.deps.telemetryPrivacyPolicy.shouldCaptureArtifact(args)) {
81
+ return NoOpTelemetryArtifactReference.value;
82
+ }
83
+ const observedAt = new Date();
84
+ const artifact = await this.deps.telemetryArtifactStore.save({
85
+ traceId: this.traceId,
86
+ spanId: this.spanId,
87
+ runId: this.deps.runId,
88
+ workflowId: this.deps.workflowId,
89
+ nodeId: this.nodeId,
90
+ activationId: this.activationId,
91
+ kind: args.kind,
92
+ contentType: args.contentType,
93
+ previewText: this.deps.telemetryPrivacyPolicy.trimPreviewText(args.previewText),
94
+ previewJson: args.previewJson,
95
+ payloadText: args.payloadText,
96
+ payloadJson: args.payloadJson,
97
+ bytes: args.bytes,
98
+ truncated: args.truncated,
99
+ expiresAt: args.expiresAt,
100
+ retentionExpiresAt: this.deps.telemetryRetentionTimestampFactory.createArtifactExpiry(
101
+ this.deps.policySnapshot,
102
+ observedAt,
103
+ ),
104
+ });
105
+ await this.touchTraceContextExpiry(
106
+ this.deps.telemetryRetentionTimestampFactory.createTraceContextExpiry(this.deps.policySnapshot, observedAt),
107
+ );
108
+ return {
109
+ artifactId: artifact.artifactId,
110
+ traceId: artifact.traceId,
111
+ spanId: artifact.spanId,
112
+ };
113
+ }
114
+
115
+ async end(args: TelemetrySpanEnd = {}): Promise<void> {
116
+ await this.upsert({
117
+ status: args.status === "error" ? "failed" : "completed",
118
+ statusMessage: args.statusMessage,
119
+ endTime: (args.endedAt ?? new Date()).toISOString(),
120
+ attributes: args.attributes,
121
+ });
122
+ }
123
+
124
+ async markStarted(): Promise<void> {
125
+ await this.upsert({
126
+ status: "running",
127
+ startTime: (this.initialStartTime ?? new Date()).toISOString(),
128
+ attributes: this.initialAttributes,
129
+ modelName: this.modelName,
130
+ connectionInvocationId: this.connectionInvocationId,
131
+ });
132
+ }
133
+
134
+ protected async upsert(update: Partial<TelemetrySpanUpsert>): Promise<void> {
135
+ const enrichment = await this.resolveEnrichment();
136
+ const observedAt = this.resolveObservedAt(update);
137
+ const retentionExpiresAt =
138
+ update.retentionExpiresAt ??
139
+ this.deps.telemetryRetentionTimestampFactory.createSpanExpiry(this.deps.policySnapshot, observedAt);
140
+ await this.deps.telemetrySpanStore.upsert({
141
+ traceId: this.traceId,
142
+ spanId: this.spanId,
143
+ parentSpanId: this.parentSpanId,
144
+ runId: this.deps.runId,
145
+ workflowId: this.deps.workflowId,
146
+ nodeId: this.nodeId,
147
+ activationId: this.activationId,
148
+ name: this.spanName,
149
+ kind: this.spanKind,
150
+ workflowFolder: enrichment.workflowFolder,
151
+ nodeType: enrichment.nodeType,
152
+ nodeRole: enrichment.nodeRole,
153
+ retentionExpiresAt,
154
+ ...update,
155
+ });
156
+ await this.touchTraceContextExpiry(
157
+ this.deps.telemetryRetentionTimestampFactory.createTraceContextExpiry(this.deps.policySnapshot, observedAt),
158
+ );
159
+ }
160
+
161
+ private async resolveEnrichment(): Promise<
162
+ Readonly<{ workflowFolder?: string; nodeType?: string; nodeRole?: string }>
163
+ > {
164
+ if (this.nodeId) {
165
+ return await this.deps.telemetryEnricherChain.enrichNode({
166
+ workflowId: this.deps.workflowId,
167
+ nodeId: this.nodeId,
168
+ });
169
+ }
170
+ return await this.deps.telemetryEnricherChain.enrichRun(this.deps.workflowId);
171
+ }
172
+
173
+ private resolveObservedAt(update: Partial<TelemetrySpanUpsert>): Date {
174
+ const iso = update.endTime ?? update.startTime;
175
+ return iso ? new Date(iso) : new Date();
176
+ }
177
+
178
+ private async touchTraceContextExpiry(expiresAt: string | undefined): Promise<void> {
179
+ await this.deps.runTraceContextRepository.upsertExpiry({
180
+ runId: this.deps.runId,
181
+ expiresAt,
182
+ });
183
+ }
184
+
185
+ protected toStringAttribute(value: TelemetryAttributes[string]): string | undefined {
186
+ return typeof value === "string" ? value : undefined;
187
+ }
188
+ }
@@ -0,0 +1,85 @@
1
+ import type { WorkflowDefinition } from "@codemation/core";
2
+ import { inject, injectable } from "@codemation/core";
3
+ import { ApplicationTokens } from "../../applicationTokens";
4
+ import type { WorkflowDefinitionRepository } from "../../domain/workflows/WorkflowDefinitionRepository";
5
+
6
+ export interface TelemetryNodeMetadata {
7
+ readonly workflowFolder?: string;
8
+ readonly nodeType?: string;
9
+ readonly nodeRole?: string;
10
+ }
11
+
12
+ @injectable()
13
+ export class TelemetryEnricherChain {
14
+ private readonly definitionsByWorkflowId = new Map<string, WorkflowDefinition | null>();
15
+
16
+ constructor(
17
+ @inject(ApplicationTokens.WorkflowDefinitionRepository)
18
+ private readonly workflowDefinitionRepository: WorkflowDefinitionRepository,
19
+ ) {}
20
+
21
+ async enrichNode(args: Readonly<{ workflowId: string; nodeId: string }>): Promise<TelemetryNodeMetadata> {
22
+ const workflow = await this.loadDefinition(args.workflowId);
23
+ if (!workflow) {
24
+ return {};
25
+ }
26
+ const node = workflow.nodes.find((entry) => entry.id === args.nodeId);
27
+ if (!node) {
28
+ return {
29
+ workflowFolder: this.toWorkflowFolder(workflow),
30
+ };
31
+ }
32
+ return {
33
+ workflowFolder: this.toWorkflowFolder(workflow),
34
+ nodeType: this.toNodeType(node),
35
+ nodeRole: this.toNodeRole(workflow, args.nodeId),
36
+ };
37
+ }
38
+
39
+ async enrichRun(workflowId: string): Promise<Readonly<{ workflowFolder?: string }>> {
40
+ const workflow = await this.loadDefinition(workflowId);
41
+ return {
42
+ workflowFolder: workflow ? this.toWorkflowFolder(workflow) : undefined,
43
+ };
44
+ }
45
+
46
+ private async loadDefinition(workflowId: string): Promise<WorkflowDefinition | undefined> {
47
+ const key = decodeURIComponent(workflowId);
48
+ if (this.definitionsByWorkflowId.has(key)) {
49
+ return this.definitionsByWorkflowId.get(key) ?? undefined;
50
+ }
51
+ const loaded = (await this.workflowDefinitionRepository.getDefinition(key)) ?? null;
52
+ this.definitionsByWorkflowId.set(key, loaded);
53
+ return loaded ?? undefined;
54
+ }
55
+
56
+ private toWorkflowFolder(workflow: WorkflowDefinition): string | undefined {
57
+ const segments = workflow.discoveryPathSegments ?? [];
58
+ if (segments.length === 0) {
59
+ return undefined;
60
+ }
61
+ return segments.slice(0, -1).join("/");
62
+ }
63
+
64
+ private toNodeType(node: WorkflowDefinition["nodes"][number]): string | undefined {
65
+ const token = node.type;
66
+ if (typeof token === "function" && token.name) {
67
+ return token.name;
68
+ }
69
+ if (typeof token === "symbol") {
70
+ return token.description ?? token.toString();
71
+ }
72
+ return undefined;
73
+ }
74
+
75
+ private toNodeRole(workflow: WorkflowDefinition, nodeId: string): string {
76
+ const connection = workflow.connections?.find((entry) => entry.childNodeIds.includes(nodeId));
77
+ if (!connection) {
78
+ return "workflowNode";
79
+ }
80
+ if (connection.connectionName === "llm") {
81
+ return "languageModel";
82
+ }
83
+ return "tool";
84
+ }
85
+ }
@@ -0,0 +1,19 @@
1
+ import { injectable } from "@codemation/core";
2
+ import type { TelemetryArtifactAttachment } from "@codemation/core";
3
+
4
+ @injectable()
5
+ export class TelemetryPrivacyPolicy {
6
+ private readonly captureArtifacts = false;
7
+ private readonly maxPreviewLength = 1_000;
8
+
9
+ shouldCaptureArtifact(_: TelemetryArtifactAttachment): boolean {
10
+ return this.captureArtifacts;
11
+ }
12
+
13
+ trimPreviewText(value: string | undefined): string | undefined {
14
+ if (!value) {
15
+ return undefined;
16
+ }
17
+ return value.length > this.maxPreviewLength ? value.slice(0, this.maxPreviewLength) : value;
18
+ }
19
+ }