@symerian/symi 3.0.18 → 3.0.19
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/build-info.json +3 -3
- package/dist/canvas-host/a2ui/.bundle.hash +1 -1
- package/package.json +1 -1
- package/extensions/copilot-proxy/README.md +0 -24
- package/extensions/copilot-proxy/index.ts +0 -154
- package/extensions/copilot-proxy/node_modules/.bin/symi +0 -21
- package/extensions/copilot-proxy/package.json +0 -15
- package/extensions/copilot-proxy/symi.plugin.json +0 -9
- package/extensions/device-pair/index.ts +0 -642
- package/extensions/device-pair/symi.plugin.json +0 -20
- package/extensions/diagnostics-otel/index.ts +0 -15
- package/extensions/diagnostics-otel/node_modules/.bin/acorn +0 -21
- package/extensions/diagnostics-otel/node_modules/.bin/symi +0 -21
- package/extensions/diagnostics-otel/package.json +0 -27
- package/extensions/diagnostics-otel/src/service.test.ts +0 -290
- package/extensions/diagnostics-otel/src/service.ts +0 -666
- package/extensions/diagnostics-otel/symi.plugin.json +0 -8
- package/extensions/google-antigravity-auth/README.md +0 -24
- package/extensions/google-antigravity-auth/index.ts +0 -424
- package/extensions/google-antigravity-auth/node_modules/.bin/symi +0 -21
- package/extensions/google-antigravity-auth/package.json +0 -15
- package/extensions/google-antigravity-auth/symi.plugin.json +0 -9
- package/extensions/google-gemini-cli-auth/README.md +0 -35
- package/extensions/google-gemini-cli-auth/index.ts +0 -75
- package/extensions/google-gemini-cli-auth/node_modules/.bin/symi +0 -21
- package/extensions/google-gemini-cli-auth/oauth.test.ts +0 -162
- package/extensions/google-gemini-cli-auth/oauth.ts +0 -636
- package/extensions/google-gemini-cli-auth/package.json +0 -15
- package/extensions/google-gemini-cli-auth/symi.plugin.json +0 -9
- package/extensions/learning-loop/index.ts +0 -159
- package/extensions/learning-loop/node_modules/.bin/symi +0 -21
- package/extensions/learning-loop/package.json +0 -18
- package/extensions/learning-loop/src/analytics/gateway-methods.ts +0 -230
- package/extensions/learning-loop/src/analytics/metrics-aggregator.ts +0 -153
- package/extensions/learning-loop/src/capture/run-tracker.ts +0 -181
- package/extensions/learning-loop/src/capture/serializer.ts +0 -74
- package/extensions/learning-loop/src/db.ts +0 -583
- package/extensions/learning-loop/src/feedback/explicit-feedback.ts +0 -58
- package/extensions/learning-loop/src/feedback/implicit-signals.ts +0 -89
- package/extensions/learning-loop/src/graph/edge-inference.ts +0 -189
- package/extensions/learning-loop/src/graph/graph-retrieval.ts +0 -144
- package/extensions/learning-loop/src/graph/graph-store.ts +0 -183
- package/extensions/learning-loop/src/hooks.ts +0 -244
- package/extensions/learning-loop/src/injection/cache.ts +0 -73
- package/extensions/learning-loop/src/injection/context-injector.ts +0 -104
- package/extensions/learning-loop/src/injection/prompt-builder.ts +0 -43
- package/extensions/learning-loop/src/learning/embedding-bridge.ts +0 -54
- package/extensions/learning-loop/src/learning/learning-extractor.ts +0 -217
- package/extensions/learning-loop/src/learning/learning-store.ts +0 -158
- package/extensions/learning-loop/src/learning/retrieval.ts +0 -87
- package/extensions/learning-loop/src/math/confidence-intervals.ts +0 -62
- package/extensions/learning-loop/src/math/ewma.ts +0 -51
- package/extensions/learning-loop/src/math/weighted-scorer.ts +0 -42
- package/extensions/learning-loop/src/schema.ts +0 -176
- package/extensions/learning-loop/src/scoring/normalization.ts +0 -32
- package/extensions/learning-loop/src/scoring/quality-engine.ts +0 -78
- package/extensions/learning-loop/src/scoring/signal-extractors.ts +0 -155
- package/extensions/learning-loop/src/test/context-injector.test.ts +0 -142
- package/extensions/learning-loop/src/test/fixes.test.ts +0 -1286
- package/extensions/learning-loop/src/test/graph.test.ts +0 -711
- package/extensions/learning-loop/src/test/integration.test.ts +0 -312
- package/extensions/learning-loop/src/test/learning-store.test.ts +0 -191
- package/extensions/learning-loop/src/test/math.test.ts +0 -148
- package/extensions/learning-loop/src/test/quality-engine.test.ts +0 -231
- package/extensions/learning-loop/src/test/run-tracker.test.ts +0 -143
- package/extensions/learning-loop/src/types.ts +0 -281
- package/extensions/learning-loop/symi.plugin.json +0 -46
- package/extensions/llm-task/README.md +0 -97
- package/extensions/llm-task/index.ts +0 -6
- package/extensions/llm-task/package.json +0 -12
- package/extensions/llm-task/src/llm-task-tool.test.ts +0 -138
- package/extensions/llm-task/src/llm-task-tool.ts +0 -249
- package/extensions/llm-task/symi.plugin.json +0 -21
- package/extensions/memory-lancedb/config.ts +0 -161
- package/extensions/memory-lancedb/index.test.ts +0 -330
- package/extensions/memory-lancedb/index.ts +0 -670
- package/extensions/memory-lancedb/node_modules/.bin/arrow2csv +0 -21
- package/extensions/memory-lancedb/node_modules/.bin/openai +0 -21
- package/extensions/memory-lancedb/node_modules/.bin/symi +0 -21
- package/extensions/memory-lancedb/package.json +0 -20
- package/extensions/memory-lancedb/symi.plugin.json +0 -71
- package/extensions/minimax-portal-auth/README.md +0 -33
- package/extensions/minimax-portal-auth/index.ts +0 -161
- package/extensions/minimax-portal-auth/node_modules/.bin/symi +0 -21
- package/extensions/minimax-portal-auth/oauth.ts +0 -247
- package/extensions/minimax-portal-auth/package.json +0 -15
- package/extensions/minimax-portal-auth/symi.plugin.json +0 -9
- package/extensions/model-equalizer/index.ts +0 -80
- package/extensions/model-equalizer/skills/model-equalizer/SKILL.md +0 -58
- package/extensions/model-equalizer/src/detection.ts +0 -62
- package/extensions/model-equalizer/src/enhancer.ts +0 -63
- package/extensions/model-equalizer/src/test/detection.test.ts +0 -218
- package/extensions/model-equalizer/src/test/enhancer.test.ts +0 -137
- package/extensions/model-equalizer/src/test/integration.test.ts +0 -185
- package/extensions/model-equalizer/src/types.ts +0 -24
- package/extensions/model-equalizer/symi.plugin.json +0 -12
- package/extensions/phone-control/index.ts +0 -421
- package/extensions/phone-control/symi.plugin.json +0 -10
- package/extensions/pipeline/README.md +0 -75
- package/extensions/pipeline/SKILL.md +0 -97
- package/extensions/pipeline/index.ts +0 -18
- package/extensions/pipeline/package.json +0 -11
- package/extensions/pipeline/src/pipeline-tool.test.ts +0 -345
- package/extensions/pipeline/src/pipeline-tool.ts +0 -266
- package/extensions/pipeline/src/windows-spawn.test.ts +0 -148
- package/extensions/pipeline/src/windows-spawn.ts +0 -193
- package/extensions/pipeline/symi.plugin.json +0 -10
- package/extensions/qwen-portal-auth/README.md +0 -24
- package/extensions/qwen-portal-auth/index.ts +0 -134
- package/extensions/qwen-portal-auth/oauth.ts +0 -190
- package/extensions/qwen-portal-auth/symi.plugin.json +0 -9
- package/extensions/talk-voice/index.ts +0 -150
- package/extensions/talk-voice/symi.plugin.json +0 -10
- package/extensions/thread-ownership/index.test.ts +0 -180
- package/extensions/thread-ownership/index.ts +0 -133
- package/extensions/thread-ownership/symi.plugin.json +0 -28
|
@@ -1,666 +0,0 @@
|
|
|
1
|
-
import { metrics, trace, SpanStatusCode } from "@opentelemetry/api";
|
|
2
|
-
import type { SeverityNumber } from "@opentelemetry/api-logs";
|
|
3
|
-
import { OTLPLogExporter } from "@opentelemetry/exporter-logs-otlp-http";
|
|
4
|
-
import { OTLPMetricExporter } from "@opentelemetry/exporter-metrics-otlp-http";
|
|
5
|
-
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
|
|
6
|
-
import { resourceFromAttributes } from "@opentelemetry/resources";
|
|
7
|
-
import { BatchLogRecordProcessor, LoggerProvider } from "@opentelemetry/sdk-logs";
|
|
8
|
-
import { PeriodicExportingMetricReader } from "@opentelemetry/sdk-metrics";
|
|
9
|
-
import { NodeSDK } from "@opentelemetry/sdk-node";
|
|
10
|
-
import { ParentBasedSampler, TraceIdRatioBasedSampler } from "@opentelemetry/sdk-trace-base";
|
|
11
|
-
import { ATTR_SERVICE_NAME } from "@opentelemetry/semantic-conventions";
|
|
12
|
-
import type { DiagnosticEventPayload, SymiPluginService } from "symi/plugin-sdk";
|
|
13
|
-
import { onDiagnosticEvent, registerLogTransport } from "symi/plugin-sdk";
|
|
14
|
-
|
|
15
|
-
const DEFAULT_SERVICE_NAME = "symi";
|
|
16
|
-
|
|
17
|
-
function normalizeEndpoint(endpoint?: string): string | undefined {
|
|
18
|
-
const trimmed = endpoint?.trim();
|
|
19
|
-
return trimmed ? trimmed.replace(/\/+$/, "") : undefined;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function resolveOtelUrl(endpoint: string | undefined, path: string): string | undefined {
|
|
23
|
-
if (!endpoint) {
|
|
24
|
-
return undefined;
|
|
25
|
-
}
|
|
26
|
-
const endpointWithoutQueryOrFragment = endpoint.split(/[?#]/, 1)[0] ?? endpoint;
|
|
27
|
-
if (/\/v1\/(?:traces|metrics|logs)$/i.test(endpointWithoutQueryOrFragment)) {
|
|
28
|
-
return endpoint;
|
|
29
|
-
}
|
|
30
|
-
return `${endpoint}/${path}`;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function resolveSampleRate(value: number | undefined): number | undefined {
|
|
34
|
-
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
35
|
-
return undefined;
|
|
36
|
-
}
|
|
37
|
-
if (value < 0 || value > 1) {
|
|
38
|
-
return undefined;
|
|
39
|
-
}
|
|
40
|
-
return value;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function formatError(err: unknown): string {
|
|
44
|
-
if (err instanceof Error) {
|
|
45
|
-
return err.stack ?? err.message;
|
|
46
|
-
}
|
|
47
|
-
if (typeof err === "string") {
|
|
48
|
-
return err;
|
|
49
|
-
}
|
|
50
|
-
try {
|
|
51
|
-
return JSON.stringify(err);
|
|
52
|
-
} catch {
|
|
53
|
-
return String(err);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export function createDiagnosticsOtelService(): SymiPluginService {
|
|
58
|
-
let sdk: NodeSDK | null = null;
|
|
59
|
-
let logProvider: LoggerProvider | null = null;
|
|
60
|
-
let stopLogTransport: (() => void) | null = null;
|
|
61
|
-
let unsubscribe: (() => void) | null = null;
|
|
62
|
-
|
|
63
|
-
return {
|
|
64
|
-
id: "diagnostics-otel",
|
|
65
|
-
async start(ctx) {
|
|
66
|
-
const cfg = ctx.config.diagnostics;
|
|
67
|
-
const otel = cfg?.otel;
|
|
68
|
-
if (!cfg?.enabled || !otel?.enabled) {
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
const protocol = otel.protocol ?? process.env.OTEL_EXPORTER_OTLP_PROTOCOL ?? "http/protobuf";
|
|
73
|
-
if (protocol !== "http/protobuf") {
|
|
74
|
-
ctx.logger.warn(`diagnostics-otel: unsupported protocol ${protocol}`);
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
const endpoint = normalizeEndpoint(otel.endpoint ?? process.env.OTEL_EXPORTER_OTLP_ENDPOINT);
|
|
79
|
-
const headers = otel.headers ?? undefined;
|
|
80
|
-
const serviceName =
|
|
81
|
-
otel.serviceName?.trim() || process.env.OTEL_SERVICE_NAME || DEFAULT_SERVICE_NAME;
|
|
82
|
-
const sampleRate = resolveSampleRate(otel.sampleRate);
|
|
83
|
-
|
|
84
|
-
const tracesEnabled = otel.traces !== false;
|
|
85
|
-
const metricsEnabled = otel.metrics !== false;
|
|
86
|
-
const logsEnabled = otel.logs === true;
|
|
87
|
-
if (!tracesEnabled && !metricsEnabled && !logsEnabled) {
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const resource = resourceFromAttributes({
|
|
92
|
-
[ATTR_SERVICE_NAME]: serviceName,
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
const traceUrl = resolveOtelUrl(endpoint, "v1/traces");
|
|
96
|
-
const metricUrl = resolveOtelUrl(endpoint, "v1/metrics");
|
|
97
|
-
const logUrl = resolveOtelUrl(endpoint, "v1/logs");
|
|
98
|
-
const traceExporter = tracesEnabled
|
|
99
|
-
? new OTLPTraceExporter({
|
|
100
|
-
...(traceUrl ? { url: traceUrl } : {}),
|
|
101
|
-
...(headers ? { headers } : {}),
|
|
102
|
-
})
|
|
103
|
-
: undefined;
|
|
104
|
-
|
|
105
|
-
const metricExporter = metricsEnabled
|
|
106
|
-
? new OTLPMetricExporter({
|
|
107
|
-
...(metricUrl ? { url: metricUrl } : {}),
|
|
108
|
-
...(headers ? { headers } : {}),
|
|
109
|
-
})
|
|
110
|
-
: undefined;
|
|
111
|
-
|
|
112
|
-
const metricReader = metricExporter
|
|
113
|
-
? new PeriodicExportingMetricReader({
|
|
114
|
-
exporter: metricExporter,
|
|
115
|
-
...(typeof otel.flushIntervalMs === "number"
|
|
116
|
-
? { exportIntervalMillis: Math.max(1000, otel.flushIntervalMs) }
|
|
117
|
-
: {}),
|
|
118
|
-
})
|
|
119
|
-
: undefined;
|
|
120
|
-
|
|
121
|
-
if (tracesEnabled || metricsEnabled) {
|
|
122
|
-
sdk = new NodeSDK({
|
|
123
|
-
resource,
|
|
124
|
-
...(traceExporter ? { traceExporter } : {}),
|
|
125
|
-
...(metricReader ? { metricReader } : {}),
|
|
126
|
-
...(sampleRate !== undefined
|
|
127
|
-
? {
|
|
128
|
-
sampler: new ParentBasedSampler({
|
|
129
|
-
root: new TraceIdRatioBasedSampler(sampleRate),
|
|
130
|
-
}),
|
|
131
|
-
}
|
|
132
|
-
: {}),
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
try {
|
|
136
|
-
await sdk.start();
|
|
137
|
-
} catch (err) {
|
|
138
|
-
ctx.logger.error(`diagnostics-otel: failed to start SDK: ${formatError(err)}`);
|
|
139
|
-
throw err;
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
const logSeverityMap: Record<string, SeverityNumber> = {
|
|
144
|
-
TRACE: 1 as SeverityNumber,
|
|
145
|
-
DEBUG: 5 as SeverityNumber,
|
|
146
|
-
INFO: 9 as SeverityNumber,
|
|
147
|
-
WARN: 13 as SeverityNumber,
|
|
148
|
-
ERROR: 17 as SeverityNumber,
|
|
149
|
-
FATAL: 21 as SeverityNumber,
|
|
150
|
-
};
|
|
151
|
-
|
|
152
|
-
const meter = metrics.getMeter("symi");
|
|
153
|
-
const tracer = trace.getTracer("symi");
|
|
154
|
-
|
|
155
|
-
const tokensCounter = meter.createCounter("symi.tokens", {
|
|
156
|
-
unit: "1",
|
|
157
|
-
description: "Token usage by type",
|
|
158
|
-
});
|
|
159
|
-
const costCounter = meter.createCounter("symi.cost.usd", {
|
|
160
|
-
unit: "1",
|
|
161
|
-
description: "Estimated model cost (USD)",
|
|
162
|
-
});
|
|
163
|
-
const durationHistogram = meter.createHistogram("symi.run.duration_ms", {
|
|
164
|
-
unit: "ms",
|
|
165
|
-
description: "Agent run duration",
|
|
166
|
-
});
|
|
167
|
-
const contextHistogram = meter.createHistogram("symi.context.tokens", {
|
|
168
|
-
unit: "1",
|
|
169
|
-
description: "Context window size and usage",
|
|
170
|
-
});
|
|
171
|
-
const webhookReceivedCounter = meter.createCounter("symi.webhook.received", {
|
|
172
|
-
unit: "1",
|
|
173
|
-
description: "Webhook requests received",
|
|
174
|
-
});
|
|
175
|
-
const webhookErrorCounter = meter.createCounter("symi.webhook.error", {
|
|
176
|
-
unit: "1",
|
|
177
|
-
description: "Webhook processing errors",
|
|
178
|
-
});
|
|
179
|
-
const webhookDurationHistogram = meter.createHistogram("symi.webhook.duration_ms", {
|
|
180
|
-
unit: "ms",
|
|
181
|
-
description: "Webhook processing duration",
|
|
182
|
-
});
|
|
183
|
-
const messageQueuedCounter = meter.createCounter("symi.message.queued", {
|
|
184
|
-
unit: "1",
|
|
185
|
-
description: "Messages queued for processing",
|
|
186
|
-
});
|
|
187
|
-
const messageProcessedCounter = meter.createCounter("symi.message.processed", {
|
|
188
|
-
unit: "1",
|
|
189
|
-
description: "Messages processed by outcome",
|
|
190
|
-
});
|
|
191
|
-
const messageDurationHistogram = meter.createHistogram("symi.message.duration_ms", {
|
|
192
|
-
unit: "ms",
|
|
193
|
-
description: "Message processing duration",
|
|
194
|
-
});
|
|
195
|
-
const queueDepthHistogram = meter.createHistogram("symi.queue.depth", {
|
|
196
|
-
unit: "1",
|
|
197
|
-
description: "Queue depth on enqueue/dequeue",
|
|
198
|
-
});
|
|
199
|
-
const queueWaitHistogram = meter.createHistogram("symi.queue.wait_ms", {
|
|
200
|
-
unit: "ms",
|
|
201
|
-
description: "Queue wait time before execution",
|
|
202
|
-
});
|
|
203
|
-
const laneEnqueueCounter = meter.createCounter("symi.queue.lane.enqueue", {
|
|
204
|
-
unit: "1",
|
|
205
|
-
description: "Command queue lane enqueue events",
|
|
206
|
-
});
|
|
207
|
-
const laneDequeueCounter = meter.createCounter("symi.queue.lane.dequeue", {
|
|
208
|
-
unit: "1",
|
|
209
|
-
description: "Command queue lane dequeue events",
|
|
210
|
-
});
|
|
211
|
-
const sessionStateCounter = meter.createCounter("symi.session.state", {
|
|
212
|
-
unit: "1",
|
|
213
|
-
description: "Session state transitions",
|
|
214
|
-
});
|
|
215
|
-
const sessionStuckCounter = meter.createCounter("symi.session.stuck", {
|
|
216
|
-
unit: "1",
|
|
217
|
-
description: "Sessions stuck in processing",
|
|
218
|
-
});
|
|
219
|
-
const sessionStuckAgeHistogram = meter.createHistogram("symi.session.stuck_age_ms", {
|
|
220
|
-
unit: "ms",
|
|
221
|
-
description: "Age of stuck sessions",
|
|
222
|
-
});
|
|
223
|
-
const runAttemptCounter = meter.createCounter("symi.run.attempt", {
|
|
224
|
-
unit: "1",
|
|
225
|
-
description: "Run attempts",
|
|
226
|
-
});
|
|
227
|
-
|
|
228
|
-
if (logsEnabled) {
|
|
229
|
-
const logExporter = new OTLPLogExporter({
|
|
230
|
-
...(logUrl ? { url: logUrl } : {}),
|
|
231
|
-
...(headers ? { headers } : {}),
|
|
232
|
-
});
|
|
233
|
-
const logProcessor = new BatchLogRecordProcessor(
|
|
234
|
-
logExporter,
|
|
235
|
-
typeof otel.flushIntervalMs === "number"
|
|
236
|
-
? { scheduledDelayMillis: Math.max(1000, otel.flushIntervalMs) }
|
|
237
|
-
: {},
|
|
238
|
-
);
|
|
239
|
-
logProvider = new LoggerProvider({
|
|
240
|
-
resource,
|
|
241
|
-
processors: [logProcessor],
|
|
242
|
-
});
|
|
243
|
-
const otelLogger = logProvider.getLogger("symi");
|
|
244
|
-
|
|
245
|
-
stopLogTransport = registerLogTransport((logObj) => {
|
|
246
|
-
try {
|
|
247
|
-
const safeStringify = (value: unknown) => {
|
|
248
|
-
try {
|
|
249
|
-
return JSON.stringify(value);
|
|
250
|
-
} catch {
|
|
251
|
-
return String(value);
|
|
252
|
-
}
|
|
253
|
-
};
|
|
254
|
-
const meta = (logObj as Record<string, unknown>)._meta as
|
|
255
|
-
| {
|
|
256
|
-
logLevelName?: string;
|
|
257
|
-
date?: Date;
|
|
258
|
-
name?: string;
|
|
259
|
-
parentNames?: string[];
|
|
260
|
-
path?: {
|
|
261
|
-
filePath?: string;
|
|
262
|
-
fileLine?: string;
|
|
263
|
-
fileColumn?: string;
|
|
264
|
-
filePathWithLine?: string;
|
|
265
|
-
method?: string;
|
|
266
|
-
};
|
|
267
|
-
}
|
|
268
|
-
| undefined;
|
|
269
|
-
const logLevelName = meta?.logLevelName ?? "INFO";
|
|
270
|
-
const severityNumber = logSeverityMap[logLevelName] ?? (9 as SeverityNumber);
|
|
271
|
-
|
|
272
|
-
const numericArgs = Object.entries(logObj)
|
|
273
|
-
.filter(([key]) => /^\d+$/.test(key))
|
|
274
|
-
.toSorted((a, b) => Number(a[0]) - Number(b[0]))
|
|
275
|
-
.map(([, value]) => value);
|
|
276
|
-
|
|
277
|
-
let bindings: Record<string, unknown> | undefined;
|
|
278
|
-
if (typeof numericArgs[0] === "string" && numericArgs[0].trim().startsWith("{")) {
|
|
279
|
-
try {
|
|
280
|
-
const parsed = JSON.parse(numericArgs[0]);
|
|
281
|
-
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
282
|
-
bindings = parsed as Record<string, unknown>;
|
|
283
|
-
numericArgs.shift();
|
|
284
|
-
}
|
|
285
|
-
} catch {
|
|
286
|
-
// ignore malformed json bindings
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
let message = "";
|
|
291
|
-
if (numericArgs.length > 0 && typeof numericArgs[numericArgs.length - 1] === "string") {
|
|
292
|
-
message = String(numericArgs.pop());
|
|
293
|
-
} else if (numericArgs.length === 1) {
|
|
294
|
-
message = safeStringify(numericArgs[0]);
|
|
295
|
-
numericArgs.length = 0;
|
|
296
|
-
}
|
|
297
|
-
if (!message) {
|
|
298
|
-
message = "log";
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
const attributes: Record<string, string | number | boolean> = {
|
|
302
|
-
"symi.log.level": logLevelName,
|
|
303
|
-
};
|
|
304
|
-
if (meta?.name) {
|
|
305
|
-
attributes["symi.logger"] = meta.name;
|
|
306
|
-
}
|
|
307
|
-
if (meta?.parentNames?.length) {
|
|
308
|
-
attributes["symi.logger.parents"] = meta.parentNames.join(".");
|
|
309
|
-
}
|
|
310
|
-
if (bindings) {
|
|
311
|
-
for (const [key, value] of Object.entries(bindings)) {
|
|
312
|
-
if (
|
|
313
|
-
typeof value === "string" ||
|
|
314
|
-
typeof value === "number" ||
|
|
315
|
-
typeof value === "boolean"
|
|
316
|
-
) {
|
|
317
|
-
attributes[`symi.${key}`] = value;
|
|
318
|
-
} else if (value != null) {
|
|
319
|
-
attributes[`symi.${key}`] = safeStringify(value);
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
if (numericArgs.length > 0) {
|
|
324
|
-
attributes["symi.log.args"] = safeStringify(numericArgs);
|
|
325
|
-
}
|
|
326
|
-
if (meta?.path?.filePath) {
|
|
327
|
-
attributes["code.filepath"] = meta.path.filePath;
|
|
328
|
-
}
|
|
329
|
-
if (meta?.path?.fileLine) {
|
|
330
|
-
attributes["code.lineno"] = Number(meta.path.fileLine);
|
|
331
|
-
}
|
|
332
|
-
if (meta?.path?.method) {
|
|
333
|
-
attributes["code.function"] = meta.path.method;
|
|
334
|
-
}
|
|
335
|
-
if (meta?.path?.filePathWithLine) {
|
|
336
|
-
attributes["symi.code.location"] = meta.path.filePathWithLine;
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
otelLogger.emit({
|
|
340
|
-
body: message,
|
|
341
|
-
severityText: logLevelName,
|
|
342
|
-
severityNumber,
|
|
343
|
-
attributes,
|
|
344
|
-
timestamp: meta?.date ?? new Date(),
|
|
345
|
-
});
|
|
346
|
-
} catch (err) {
|
|
347
|
-
ctx.logger.error(`diagnostics-otel: log transport failed: ${formatError(err)}`);
|
|
348
|
-
}
|
|
349
|
-
});
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
const spanWithDuration = (
|
|
353
|
-
name: string,
|
|
354
|
-
attributes: Record<string, string | number>,
|
|
355
|
-
durationMs?: number,
|
|
356
|
-
) => {
|
|
357
|
-
const startTime =
|
|
358
|
-
typeof durationMs === "number" ? Date.now() - Math.max(0, durationMs) : undefined;
|
|
359
|
-
const span = tracer.startSpan(name, {
|
|
360
|
-
attributes,
|
|
361
|
-
...(startTime ? { startTime } : {}),
|
|
362
|
-
});
|
|
363
|
-
return span;
|
|
364
|
-
};
|
|
365
|
-
|
|
366
|
-
const recordModelUsage = (evt: Extract<DiagnosticEventPayload, { type: "model.usage" }>) => {
|
|
367
|
-
const attrs = {
|
|
368
|
-
"symi.channel": evt.channel ?? "unknown",
|
|
369
|
-
"symi.provider": evt.provider ?? "unknown",
|
|
370
|
-
"symi.model": evt.model ?? "unknown",
|
|
371
|
-
};
|
|
372
|
-
|
|
373
|
-
const usage = evt.usage;
|
|
374
|
-
if (usage.input) {
|
|
375
|
-
tokensCounter.add(usage.input, { ...attrs, "symi.token": "input" });
|
|
376
|
-
}
|
|
377
|
-
if (usage.output) {
|
|
378
|
-
tokensCounter.add(usage.output, { ...attrs, "symi.token": "output" });
|
|
379
|
-
}
|
|
380
|
-
if (usage.cacheRead) {
|
|
381
|
-
tokensCounter.add(usage.cacheRead, { ...attrs, "symi.token": "cache_read" });
|
|
382
|
-
}
|
|
383
|
-
if (usage.cacheWrite) {
|
|
384
|
-
tokensCounter.add(usage.cacheWrite, { ...attrs, "symi.token": "cache_write" });
|
|
385
|
-
}
|
|
386
|
-
if (usage.promptTokens) {
|
|
387
|
-
tokensCounter.add(usage.promptTokens, { ...attrs, "symi.token": "prompt" });
|
|
388
|
-
}
|
|
389
|
-
if (usage.total) {
|
|
390
|
-
tokensCounter.add(usage.total, { ...attrs, "symi.token": "total" });
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
if (evt.costUsd) {
|
|
394
|
-
costCounter.add(evt.costUsd, attrs);
|
|
395
|
-
}
|
|
396
|
-
if (evt.durationMs) {
|
|
397
|
-
durationHistogram.record(evt.durationMs, attrs);
|
|
398
|
-
}
|
|
399
|
-
if (evt.context?.limit) {
|
|
400
|
-
contextHistogram.record(evt.context.limit, {
|
|
401
|
-
...attrs,
|
|
402
|
-
"symi.context": "limit",
|
|
403
|
-
});
|
|
404
|
-
}
|
|
405
|
-
if (evt.context?.used) {
|
|
406
|
-
contextHistogram.record(evt.context.used, {
|
|
407
|
-
...attrs,
|
|
408
|
-
"symi.context": "used",
|
|
409
|
-
});
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
if (!tracesEnabled) {
|
|
413
|
-
return;
|
|
414
|
-
}
|
|
415
|
-
const spanAttrs: Record<string, string | number> = {
|
|
416
|
-
...attrs,
|
|
417
|
-
"symi.sessionKey": evt.sessionKey ?? "",
|
|
418
|
-
"symi.sessionId": evt.sessionId ?? "",
|
|
419
|
-
"symi.tokens.input": usage.input ?? 0,
|
|
420
|
-
"symi.tokens.output": usage.output ?? 0,
|
|
421
|
-
"symi.tokens.cache_read": usage.cacheRead ?? 0,
|
|
422
|
-
"symi.tokens.cache_write": usage.cacheWrite ?? 0,
|
|
423
|
-
"symi.tokens.total": usage.total ?? 0,
|
|
424
|
-
};
|
|
425
|
-
|
|
426
|
-
const span = spanWithDuration("symi.model.usage", spanAttrs, evt.durationMs);
|
|
427
|
-
span.end();
|
|
428
|
-
};
|
|
429
|
-
|
|
430
|
-
const recordWebhookReceived = (
|
|
431
|
-
evt: Extract<DiagnosticEventPayload, { type: "webhook.received" }>,
|
|
432
|
-
) => {
|
|
433
|
-
const attrs = {
|
|
434
|
-
"symi.channel": evt.channel ?? "unknown",
|
|
435
|
-
"symi.webhook": evt.updateType ?? "unknown",
|
|
436
|
-
};
|
|
437
|
-
webhookReceivedCounter.add(1, attrs);
|
|
438
|
-
};
|
|
439
|
-
|
|
440
|
-
const recordWebhookProcessed = (
|
|
441
|
-
evt: Extract<DiagnosticEventPayload, { type: "webhook.processed" }>,
|
|
442
|
-
) => {
|
|
443
|
-
const attrs = {
|
|
444
|
-
"symi.channel": evt.channel ?? "unknown",
|
|
445
|
-
"symi.webhook": evt.updateType ?? "unknown",
|
|
446
|
-
};
|
|
447
|
-
if (typeof evt.durationMs === "number") {
|
|
448
|
-
webhookDurationHistogram.record(evt.durationMs, attrs);
|
|
449
|
-
}
|
|
450
|
-
if (!tracesEnabled) {
|
|
451
|
-
return;
|
|
452
|
-
}
|
|
453
|
-
const spanAttrs: Record<string, string | number> = { ...attrs };
|
|
454
|
-
if (evt.chatId !== undefined) {
|
|
455
|
-
spanAttrs["symi.chatId"] = String(evt.chatId);
|
|
456
|
-
}
|
|
457
|
-
const span = spanWithDuration("symi.webhook.processed", spanAttrs, evt.durationMs);
|
|
458
|
-
span.end();
|
|
459
|
-
};
|
|
460
|
-
|
|
461
|
-
const recordWebhookError = (
|
|
462
|
-
evt: Extract<DiagnosticEventPayload, { type: "webhook.error" }>,
|
|
463
|
-
) => {
|
|
464
|
-
const attrs = {
|
|
465
|
-
"symi.channel": evt.channel ?? "unknown",
|
|
466
|
-
"symi.webhook": evt.updateType ?? "unknown",
|
|
467
|
-
};
|
|
468
|
-
webhookErrorCounter.add(1, attrs);
|
|
469
|
-
if (!tracesEnabled) {
|
|
470
|
-
return;
|
|
471
|
-
}
|
|
472
|
-
const spanAttrs: Record<string, string | number> = {
|
|
473
|
-
...attrs,
|
|
474
|
-
"symi.error": evt.error,
|
|
475
|
-
};
|
|
476
|
-
if (evt.chatId !== undefined) {
|
|
477
|
-
spanAttrs["symi.chatId"] = String(evt.chatId);
|
|
478
|
-
}
|
|
479
|
-
const span = tracer.startSpan("symi.webhook.error", {
|
|
480
|
-
attributes: spanAttrs,
|
|
481
|
-
});
|
|
482
|
-
span.setStatus({ code: SpanStatusCode.ERROR, message: evt.error });
|
|
483
|
-
span.end();
|
|
484
|
-
};
|
|
485
|
-
|
|
486
|
-
const recordMessageQueued = (
|
|
487
|
-
evt: Extract<DiagnosticEventPayload, { type: "message.queued" }>,
|
|
488
|
-
) => {
|
|
489
|
-
const attrs = {
|
|
490
|
-
"symi.channel": evt.channel ?? "unknown",
|
|
491
|
-
"symi.source": evt.source ?? "unknown",
|
|
492
|
-
};
|
|
493
|
-
messageQueuedCounter.add(1, attrs);
|
|
494
|
-
if (typeof evt.queueDepth === "number") {
|
|
495
|
-
queueDepthHistogram.record(evt.queueDepth, attrs);
|
|
496
|
-
}
|
|
497
|
-
};
|
|
498
|
-
|
|
499
|
-
const recordMessageProcessed = (
|
|
500
|
-
evt: Extract<DiagnosticEventPayload, { type: "message.processed" }>,
|
|
501
|
-
) => {
|
|
502
|
-
const attrs = {
|
|
503
|
-
"symi.channel": evt.channel ?? "unknown",
|
|
504
|
-
"symi.outcome": evt.outcome ?? "unknown",
|
|
505
|
-
};
|
|
506
|
-
messageProcessedCounter.add(1, attrs);
|
|
507
|
-
if (typeof evt.durationMs === "number") {
|
|
508
|
-
messageDurationHistogram.record(evt.durationMs, attrs);
|
|
509
|
-
}
|
|
510
|
-
if (!tracesEnabled) {
|
|
511
|
-
return;
|
|
512
|
-
}
|
|
513
|
-
const spanAttrs: Record<string, string | number> = { ...attrs };
|
|
514
|
-
if (evt.sessionKey) {
|
|
515
|
-
spanAttrs["symi.sessionKey"] = evt.sessionKey;
|
|
516
|
-
}
|
|
517
|
-
if (evt.sessionId) {
|
|
518
|
-
spanAttrs["symi.sessionId"] = evt.sessionId;
|
|
519
|
-
}
|
|
520
|
-
if (evt.chatId !== undefined) {
|
|
521
|
-
spanAttrs["symi.chatId"] = String(evt.chatId);
|
|
522
|
-
}
|
|
523
|
-
if (evt.messageId !== undefined) {
|
|
524
|
-
spanAttrs["symi.messageId"] = String(evt.messageId);
|
|
525
|
-
}
|
|
526
|
-
if (evt.reason) {
|
|
527
|
-
spanAttrs["symi.reason"] = evt.reason;
|
|
528
|
-
}
|
|
529
|
-
const span = spanWithDuration("symi.message.processed", spanAttrs, evt.durationMs);
|
|
530
|
-
if (evt.outcome === "error") {
|
|
531
|
-
span.setStatus({ code: SpanStatusCode.ERROR, message: evt.error });
|
|
532
|
-
}
|
|
533
|
-
span.end();
|
|
534
|
-
};
|
|
535
|
-
|
|
536
|
-
const recordLaneEnqueue = (
|
|
537
|
-
evt: Extract<DiagnosticEventPayload, { type: "queue.lane.enqueue" }>,
|
|
538
|
-
) => {
|
|
539
|
-
const attrs = { "symi.lane": evt.lane };
|
|
540
|
-
laneEnqueueCounter.add(1, attrs);
|
|
541
|
-
queueDepthHistogram.record(evt.queueSize, attrs);
|
|
542
|
-
};
|
|
543
|
-
|
|
544
|
-
const recordLaneDequeue = (
|
|
545
|
-
evt: Extract<DiagnosticEventPayload, { type: "queue.lane.dequeue" }>,
|
|
546
|
-
) => {
|
|
547
|
-
const attrs = { "symi.lane": evt.lane };
|
|
548
|
-
laneDequeueCounter.add(1, attrs);
|
|
549
|
-
queueDepthHistogram.record(evt.queueSize, attrs);
|
|
550
|
-
if (typeof evt.waitMs === "number") {
|
|
551
|
-
queueWaitHistogram.record(evt.waitMs, attrs);
|
|
552
|
-
}
|
|
553
|
-
};
|
|
554
|
-
|
|
555
|
-
const recordSessionState = (
|
|
556
|
-
evt: Extract<DiagnosticEventPayload, { type: "session.state" }>,
|
|
557
|
-
) => {
|
|
558
|
-
const attrs: Record<string, string> = { "symi.state": evt.state };
|
|
559
|
-
if (evt.reason) {
|
|
560
|
-
attrs["symi.reason"] = evt.reason;
|
|
561
|
-
}
|
|
562
|
-
sessionStateCounter.add(1, attrs);
|
|
563
|
-
};
|
|
564
|
-
|
|
565
|
-
const recordSessionStuck = (
|
|
566
|
-
evt: Extract<DiagnosticEventPayload, { type: "session.stuck" }>,
|
|
567
|
-
) => {
|
|
568
|
-
const attrs: Record<string, string> = { "symi.state": evt.state };
|
|
569
|
-
sessionStuckCounter.add(1, attrs);
|
|
570
|
-
if (typeof evt.ageMs === "number") {
|
|
571
|
-
sessionStuckAgeHistogram.record(evt.ageMs, attrs);
|
|
572
|
-
}
|
|
573
|
-
if (!tracesEnabled) {
|
|
574
|
-
return;
|
|
575
|
-
}
|
|
576
|
-
const spanAttrs: Record<string, string | number> = { ...attrs };
|
|
577
|
-
if (evt.sessionKey) {
|
|
578
|
-
spanAttrs["symi.sessionKey"] = evt.sessionKey;
|
|
579
|
-
}
|
|
580
|
-
if (evt.sessionId) {
|
|
581
|
-
spanAttrs["symi.sessionId"] = evt.sessionId;
|
|
582
|
-
}
|
|
583
|
-
spanAttrs["symi.queueDepth"] = evt.queueDepth ?? 0;
|
|
584
|
-
spanAttrs["symi.ageMs"] = evt.ageMs;
|
|
585
|
-
const span = tracer.startSpan("symi.session.stuck", { attributes: spanAttrs });
|
|
586
|
-
span.setStatus({ code: SpanStatusCode.ERROR, message: "session stuck" });
|
|
587
|
-
span.end();
|
|
588
|
-
};
|
|
589
|
-
|
|
590
|
-
const recordRunAttempt = (evt: Extract<DiagnosticEventPayload, { type: "run.attempt" }>) => {
|
|
591
|
-
runAttemptCounter.add(1, { "symi.attempt": evt.attempt });
|
|
592
|
-
};
|
|
593
|
-
|
|
594
|
-
const recordHeartbeat = (
|
|
595
|
-
evt: Extract<DiagnosticEventPayload, { type: "diagnostic.heartbeat" }>,
|
|
596
|
-
) => {
|
|
597
|
-
queueDepthHistogram.record(evt.queued, { "symi.channel": "heartbeat" });
|
|
598
|
-
};
|
|
599
|
-
|
|
600
|
-
unsubscribe = onDiagnosticEvent((evt: DiagnosticEventPayload) => {
|
|
601
|
-
try {
|
|
602
|
-
switch (evt.type) {
|
|
603
|
-
case "model.usage":
|
|
604
|
-
recordModelUsage(evt);
|
|
605
|
-
return;
|
|
606
|
-
case "webhook.received":
|
|
607
|
-
recordWebhookReceived(evt);
|
|
608
|
-
return;
|
|
609
|
-
case "webhook.processed":
|
|
610
|
-
recordWebhookProcessed(evt);
|
|
611
|
-
return;
|
|
612
|
-
case "webhook.error":
|
|
613
|
-
recordWebhookError(evt);
|
|
614
|
-
return;
|
|
615
|
-
case "message.queued":
|
|
616
|
-
recordMessageQueued(evt);
|
|
617
|
-
return;
|
|
618
|
-
case "message.processed":
|
|
619
|
-
recordMessageProcessed(evt);
|
|
620
|
-
return;
|
|
621
|
-
case "queue.lane.enqueue":
|
|
622
|
-
recordLaneEnqueue(evt);
|
|
623
|
-
return;
|
|
624
|
-
case "queue.lane.dequeue":
|
|
625
|
-
recordLaneDequeue(evt);
|
|
626
|
-
return;
|
|
627
|
-
case "session.state":
|
|
628
|
-
recordSessionState(evt);
|
|
629
|
-
return;
|
|
630
|
-
case "session.stuck":
|
|
631
|
-
recordSessionStuck(evt);
|
|
632
|
-
return;
|
|
633
|
-
case "run.attempt":
|
|
634
|
-
recordRunAttempt(evt);
|
|
635
|
-
return;
|
|
636
|
-
case "diagnostic.heartbeat":
|
|
637
|
-
recordHeartbeat(evt);
|
|
638
|
-
return;
|
|
639
|
-
}
|
|
640
|
-
} catch (err) {
|
|
641
|
-
ctx.logger.error(
|
|
642
|
-
`diagnostics-otel: event handler failed (${evt.type}): ${formatError(err)}`,
|
|
643
|
-
);
|
|
644
|
-
}
|
|
645
|
-
});
|
|
646
|
-
|
|
647
|
-
if (logsEnabled) {
|
|
648
|
-
ctx.logger.info("diagnostics-otel: logs exporter enabled (OTLP/HTTP)");
|
|
649
|
-
}
|
|
650
|
-
},
|
|
651
|
-
async stop() {
|
|
652
|
-
unsubscribe?.();
|
|
653
|
-
unsubscribe = null;
|
|
654
|
-
stopLogTransport?.();
|
|
655
|
-
stopLogTransport = null;
|
|
656
|
-
if (logProvider) {
|
|
657
|
-
await logProvider.shutdown().catch(() => undefined);
|
|
658
|
-
logProvider = null;
|
|
659
|
-
}
|
|
660
|
-
if (sdk) {
|
|
661
|
-
await sdk.shutdown().catch(() => undefined);
|
|
662
|
-
sdk = null;
|
|
663
|
-
}
|
|
664
|
-
},
|
|
665
|
-
} satisfies SymiPluginService;
|
|
666
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
# Google Antigravity Auth (Symi plugin)
|
|
2
|
-
|
|
3
|
-
OAuth provider plugin for **Google Antigravity** (Cloud Code Assist).
|
|
4
|
-
|
|
5
|
-
## Enable
|
|
6
|
-
|
|
7
|
-
Bundled plugins are disabled by default. Enable this one:
|
|
8
|
-
|
|
9
|
-
```bash
|
|
10
|
-
symi plugins enable google-antigravity-auth
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
Restart the Gateway after enabling.
|
|
14
|
-
|
|
15
|
-
## Authenticate
|
|
16
|
-
|
|
17
|
-
```bash
|
|
18
|
-
symi models auth login --provider google-antigravity --set-default
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
## Notes
|
|
22
|
-
|
|
23
|
-
- Antigravity uses Google Cloud project quotas.
|
|
24
|
-
- If requests fail, ensure Gemini for Google Cloud is enabled.
|