neuralos 3.2.12 → 3.2.14
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/bin/gybackend.cjs +218 -48
- package/package.json +2 -2
package/bin/gybackend.cjs
CHANGED
|
@@ -367973,6 +367973,8 @@ var AgentService_v2 = class {
|
|
|
367973
367973
|
/** sessionId → ledger run id for the in-flight run (set for every run,
|
|
367974
367974
|
* unlike activeAgentRunIdsBySession which requires caller metadata). */
|
|
367975
367975
|
ledgerRunIdsBySession = /* @__PURE__ */ new Map();
|
|
367976
|
+
/** v3.2.13: gateway runId per session — used to correlate LLM trace spans. */
|
|
367977
|
+
currentRunIdBySession = /* @__PURE__ */ new Map();
|
|
367976
367978
|
constructor(terminalService, commandPolicyService, mcpToolService, skillService, memoryService, uiHistoryService, chatHistoryService, imageAttachmentService, fileTransferService) {
|
|
367977
367979
|
this.terminalService = terminalService;
|
|
367978
367980
|
this.chatHistoryService = chatHistoryService;
|
|
@@ -368619,6 +368621,7 @@ var AgentService_v2 = class {
|
|
|
368619
368621
|
let partialText = "";
|
|
368620
368622
|
let reasoningContent = "";
|
|
368621
368623
|
let debugRawChunks = [];
|
|
368624
|
+
const llmTraceStart = Date.now();
|
|
368622
368625
|
const fullResponse = await invokeWithRetryAndSanitizedInput({
|
|
368623
368626
|
helpers: this.helpers,
|
|
368624
368627
|
messages: modelInputMessages,
|
|
@@ -368816,6 +368819,26 @@ var AgentService_v2 = class {
|
|
|
368816
368819
|
debugRawChunks
|
|
368817
368820
|
);
|
|
368818
368821
|
let currentTokens = state.token_state.current_tokens;
|
|
368822
|
+
try {
|
|
368823
|
+
const traceModelName = getStreamedResponseModelName(fullResponse, debugRawChunks) || baseModel?.modelName || baseModel?.model || "unknown";
|
|
368824
|
+
const breakdown = usageInfo ? extractUsageTokenBreakdown(usageInfo.usage) : void 0;
|
|
368825
|
+
this.observability?.llmTrace?.record(
|
|
368826
|
+
{
|
|
368827
|
+
runId: state.runId,
|
|
368828
|
+
sessionId,
|
|
368829
|
+
operation: shouldUseThinkingModelOnThisPass ? "thinking" : "chat",
|
|
368830
|
+
model: traceModelName
|
|
368831
|
+
},
|
|
368832
|
+
{
|
|
368833
|
+
durationMs: Date.now() - llmTraceStart,
|
|
368834
|
+
...breakdown?.promptTokens !== void 0 ? { inputTokens: breakdown.promptTokens } : {},
|
|
368835
|
+
...breakdown?.completionTokens !== void 0 ? { outputTokens: breakdown.completionTokens } : {},
|
|
368836
|
+
...usageInfo ? { totalTokens: usageInfo.totalTokens } : {},
|
|
368837
|
+
finishReason: describeStreamedResponseFinish(fullResponse, debugRawChunks) || void 0
|
|
368838
|
+
}
|
|
368839
|
+
);
|
|
368840
|
+
} catch {
|
|
368841
|
+
}
|
|
368819
368842
|
if (usageInfo) {
|
|
368820
368843
|
currentTokens = usageInfo.totalTokens;
|
|
368821
368844
|
const modelName = getStreamedResponseModelName(fullResponse, debugRawChunks) || baseModel?.modelName || baseModel?.model || "unknown";
|
|
@@ -370899,60 +370922,99 @@ ${reminder}`;
|
|
|
370899
370922
|
const processedMessages = buildDynamicRequestHistory(messages, {
|
|
370900
370923
|
modelSupportsImage: sessionBinding.readFileSupport.image
|
|
370901
370924
|
});
|
|
370925
|
+
const llmTraceStart = Date.now();
|
|
370926
|
+
const traceResult = (error40) => {
|
|
370927
|
+
try {
|
|
370928
|
+
this.observability?.llmTrace?.record(
|
|
370929
|
+
{
|
|
370930
|
+
runId: this.currentRunIdBySession.get(sessionId),
|
|
370931
|
+
sessionId,
|
|
370932
|
+
operation: `audit.${decisionName}`,
|
|
370933
|
+
model: model?.modelName || model?.model || "unknown"
|
|
370934
|
+
},
|
|
370935
|
+
{
|
|
370936
|
+
durationMs: Date.now() - llmTraceStart,
|
|
370937
|
+
...error40 ? { error: error40 } : {}
|
|
370938
|
+
}
|
|
370939
|
+
);
|
|
370940
|
+
} catch {
|
|
370941
|
+
}
|
|
370942
|
+
};
|
|
370902
370943
|
if (sessionBinding.thinkingModelSupportsStructuredOutput) {
|
|
370903
370944
|
const structuredModel = model.withStructuredOutput(schema2, {
|
|
370904
370945
|
method: "jsonSchema"
|
|
370905
370946
|
});
|
|
370906
|
-
|
|
370907
|
-
|
|
370908
|
-
|
|
370909
|
-
|
|
370910
|
-
|
|
370911
|
-
|
|
370912
|
-
|
|
370913
|
-
|
|
370914
|
-
|
|
370915
|
-
|
|
370916
|
-
|
|
370917
|
-
|
|
370918
|
-
|
|
370919
|
-
|
|
370920
|
-
|
|
370921
|
-
|
|
370922
|
-
|
|
370923
|
-
|
|
370947
|
+
try {
|
|
370948
|
+
const result = await invokeWithRetryAndSanitizedInput({
|
|
370949
|
+
helpers: this.helpers,
|
|
370950
|
+
messages: processedMessages,
|
|
370951
|
+
modelSupportsImage: sessionBinding.readFileSupport.image,
|
|
370952
|
+
signal,
|
|
370953
|
+
operation: async (sanitizedMessages) => {
|
|
370954
|
+
return await structuredModel.invoke(sanitizedMessages, {
|
|
370955
|
+
signal
|
|
370956
|
+
});
|
|
370957
|
+
},
|
|
370958
|
+
onRetry: (attempt) => {
|
|
370959
|
+
console.log(
|
|
370960
|
+
`[AgentService_v2] Retrying thinking model decision for ${decisionName} (attempt ${attempt + 1})...`
|
|
370961
|
+
);
|
|
370962
|
+
},
|
|
370963
|
+
maxRetries: MODEL_RETRY_MAX,
|
|
370964
|
+
delaysMs: MODEL_RETRY_DELAYS_MS
|
|
370965
|
+
});
|
|
370966
|
+
traceResult();
|
|
370967
|
+
return result;
|
|
370968
|
+
} catch (err) {
|
|
370969
|
+
traceResult(err instanceof Error ? err.message : String(err));
|
|
370970
|
+
throw err;
|
|
370971
|
+
}
|
|
370924
370972
|
}
|
|
370925
370973
|
if (sessionBinding.thinkingModelSupportsObjectToolChoice) {
|
|
370926
370974
|
const functionCallingModel = model.withStructuredOutput(schema2, {
|
|
370927
370975
|
method: "functionCalling"
|
|
370928
370976
|
});
|
|
370929
|
-
|
|
370930
|
-
|
|
370931
|
-
|
|
370932
|
-
|
|
370977
|
+
try {
|
|
370978
|
+
const result = await invokeWithRetryAndSanitizedInput({
|
|
370979
|
+
helpers: this.helpers,
|
|
370980
|
+
messages: processedMessages,
|
|
370981
|
+
modelSupportsImage: sessionBinding.readFileSupport.image,
|
|
370982
|
+
signal,
|
|
370983
|
+
operation: async (sanitizedMessages) => {
|
|
370984
|
+
return await functionCallingModel.invoke(sanitizedMessages, {
|
|
370985
|
+
signal
|
|
370986
|
+
});
|
|
370987
|
+
},
|
|
370988
|
+
onRetry: (attempt) => {
|
|
370989
|
+
console.log(
|
|
370990
|
+
`[AgentService_v2] Retrying tool-call thinking decision for ${decisionName} (attempt ${attempt + 1})...`
|
|
370991
|
+
);
|
|
370992
|
+
},
|
|
370993
|
+
maxRetries: MODEL_RETRY_MAX,
|
|
370994
|
+
delaysMs: MODEL_RETRY_DELAYS_MS
|
|
370995
|
+
});
|
|
370996
|
+
traceResult();
|
|
370997
|
+
return result;
|
|
370998
|
+
} catch (err) {
|
|
370999
|
+
traceResult(err instanceof Error ? err.message : String(err));
|
|
371000
|
+
throw err;
|
|
371001
|
+
}
|
|
371002
|
+
}
|
|
371003
|
+
try {
|
|
371004
|
+
const result = await this.invokeModelDecisionByPlainToolCall(
|
|
371005
|
+
sessionId,
|
|
371006
|
+
processedMessages,
|
|
371007
|
+
schema2,
|
|
370933
371008
|
signal,
|
|
370934
|
-
|
|
370935
|
-
|
|
370936
|
-
|
|
370937
|
-
|
|
370938
|
-
|
|
370939
|
-
|
|
370940
|
-
|
|
370941
|
-
|
|
370942
|
-
);
|
|
370943
|
-
},
|
|
370944
|
-
maxRetries: MODEL_RETRY_MAX,
|
|
370945
|
-
delaysMs: MODEL_RETRY_DELAYS_MS
|
|
370946
|
-
});
|
|
371009
|
+
decisionName,
|
|
371010
|
+
"thinking"
|
|
371011
|
+
);
|
|
371012
|
+
traceResult(result);
|
|
371013
|
+
return result;
|
|
371014
|
+
} catch (err) {
|
|
371015
|
+
traceResult(err instanceof Error ? err.message : String(err));
|
|
371016
|
+
throw err;
|
|
370947
371017
|
}
|
|
370948
|
-
return await this.invokeModelDecisionByPlainToolCall(
|
|
370949
|
-
sessionId,
|
|
370950
|
-
processedMessages,
|
|
370951
|
-
schema2,
|
|
370952
|
-
signal,
|
|
370953
|
-
decisionName,
|
|
370954
|
-
"thinking"
|
|
370955
|
-
);
|
|
370956
371018
|
}
|
|
370957
371019
|
async getCompactionModelDecision(sessionId, messages, schema2, signal, decisionName) {
|
|
370958
371020
|
const sessionBinding = this.getSessionModelBinding(sessionId);
|
|
@@ -371103,6 +371165,7 @@ ${reminder}`;
|
|
|
371103
371165
|
}
|
|
371104
371166
|
const ledgerRunId = agentRunId ?? `run-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
|
371105
371167
|
this.ledgerRunIdsBySession.set(sessionId, ledgerRunId);
|
|
371168
|
+
if (runId) this.currentRunIdBySession.set(sessionId, runId);
|
|
371106
371169
|
const ledgerInputPreview = typeof input === "string" ? input : input?.text ?? "";
|
|
371107
371170
|
this.agentRunLedger?.startRun({
|
|
371108
371171
|
runId: ledgerRunId,
|
|
@@ -371208,6 +371271,7 @@ ${reminder}`;
|
|
|
371208
371271
|
if (this.ledgerRunIdsBySession.get(sessionId) === ledgerRunId) {
|
|
371209
371272
|
this.ledgerRunIdsBySession.delete(sessionId);
|
|
371210
371273
|
}
|
|
371274
|
+
this.currentRunIdBySession.delete(sessionId);
|
|
371211
371275
|
this.agentRunLedger?.finishRun(ledgerRunId, ledgerExitStatus, ledgerExitError);
|
|
371212
371276
|
await this.clearCheckpoint(sessionId);
|
|
371213
371277
|
}
|
|
@@ -387049,6 +387113,88 @@ var DriftDetector = class {
|
|
|
387049
387113
|
// ../../packages/backend/src/services/observability.ts
|
|
387050
387114
|
init_spanLedger();
|
|
387051
387115
|
|
|
387116
|
+
// ../../packages/backend/src/services/observability/llmTrace.ts
|
|
387117
|
+
init_spanLedger();
|
|
387118
|
+
var PROVIDER_FROM_MODEL_RE = /^([a-z0-9-]+)\//;
|
|
387119
|
+
function inferProvider(model) {
|
|
387120
|
+
const m2 = PROVIDER_FROM_MODEL_RE.exec(model);
|
|
387121
|
+
return m2 ? m2[1] : "unknown";
|
|
387122
|
+
}
|
|
387123
|
+
function traceIdFromRun(runId) {
|
|
387124
|
+
const stripped = runId.replace(/[^0-9a-fA-F]/g, "");
|
|
387125
|
+
if (stripped.length >= 32) return stripped.slice(0, 32);
|
|
387126
|
+
if (stripped.length === 0) return "0".repeat(32);
|
|
387127
|
+
let out = stripped;
|
|
387128
|
+
while (out.length < 32) out += stripped;
|
|
387129
|
+
return out.slice(0, 32);
|
|
387130
|
+
}
|
|
387131
|
+
var LlmTraceRecorder = class {
|
|
387132
|
+
spanLedger = null;
|
|
387133
|
+
otlpForward = null;
|
|
387134
|
+
enabled = true;
|
|
387135
|
+
setSpanLedger(ledger) {
|
|
387136
|
+
this.spanLedger = ledger;
|
|
387137
|
+
}
|
|
387138
|
+
/** Optional forwarder to an external OTLP endpoint (injected by observability.ts). */
|
|
387139
|
+
setOtlpTraceExporter(forward) {
|
|
387140
|
+
this.otlpForward = forward;
|
|
387141
|
+
}
|
|
387142
|
+
setEnabled(on) {
|
|
387143
|
+
this.enabled = on;
|
|
387144
|
+
}
|
|
387145
|
+
isEnabled() {
|
|
387146
|
+
return this.enabled && this.spanLedger !== null;
|
|
387147
|
+
}
|
|
387148
|
+
/**
|
|
387149
|
+
* Record one completed LLM call. Fire-and-forget safe: never throws.
|
|
387150
|
+
*/
|
|
387151
|
+
record(input, result) {
|
|
387152
|
+
try {
|
|
387153
|
+
if (!this.enabled || !this.spanLedger) return;
|
|
387154
|
+
const now = Date.now();
|
|
387155
|
+
const startMs = now - Math.max(0, result.durationMs);
|
|
387156
|
+
const traceId = input.runId ? traceIdFromRun(input.runId) : traceIdFromRun(input.sessionId);
|
|
387157
|
+
const spanId = newSpanId();
|
|
387158
|
+
const isError3 = Boolean(result.error);
|
|
387159
|
+
this.spanLedger.ingest({
|
|
387160
|
+
traceId,
|
|
387161
|
+
spanId,
|
|
387162
|
+
service: `llm.${input.operation}`,
|
|
387163
|
+
name: `${input.model} ${input.operation}`,
|
|
387164
|
+
startMs,
|
|
387165
|
+
durationMs: Math.max(0, result.durationMs),
|
|
387166
|
+
status: isError3 ? "error" : "ok"
|
|
387167
|
+
});
|
|
387168
|
+
if (this.otlpForward) {
|
|
387169
|
+
const attributes = [
|
|
387170
|
+
{ key: "gen_ai.system", value: { stringValue: input.provider || inferProvider(input.model) } },
|
|
387171
|
+
{ key: "gen_ai.request.model", value: { stringValue: input.model } },
|
|
387172
|
+
{ key: "gen_ai.operation.name", value: { stringValue: input.operation } },
|
|
387173
|
+
{ key: "session.id", value: { stringValue: input.sessionId } }
|
|
387174
|
+
];
|
|
387175
|
+
if (typeof result.inputTokens === "number") attributes.push({ key: "gen_ai.usage.prompt_tokens", value: { intValue: result.inputTokens } });
|
|
387176
|
+
if (typeof result.outputTokens === "number") attributes.push({ key: "gen_ai.usage.completion_tokens", value: { intValue: result.outputTokens } });
|
|
387177
|
+
if (typeof result.totalTokens === "number") attributes.push({ key: "gen_ai.usage.total_tokens", value: { intValue: result.totalTokens } });
|
|
387178
|
+
if (result.finishReason) attributes.push({ key: "gen_ai.response.finish_reasons", value: { stringValue: result.finishReason } });
|
|
387179
|
+
if (result.error) attributes.push({ key: "error.message", value: { stringValue: result.error.slice(0, 500) } });
|
|
387180
|
+
this.otlpForward([
|
|
387181
|
+
{
|
|
387182
|
+
traceId,
|
|
387183
|
+
spanId,
|
|
387184
|
+
parentSpanId: "",
|
|
387185
|
+
name: `${input.operation} ${input.model}`,
|
|
387186
|
+
startTimeUnixNano: String(BigInt(Math.floor(startMs)) * 1000000n),
|
|
387187
|
+
endTimeUnixNano: String(BigInt(Math.floor(now)) * 1000000n),
|
|
387188
|
+
attributes,
|
|
387189
|
+
status: { code: isError3 ? 2 : 1 }
|
|
387190
|
+
}
|
|
387191
|
+
]);
|
|
387192
|
+
}
|
|
387193
|
+
} catch {
|
|
387194
|
+
}
|
|
387195
|
+
}
|
|
387196
|
+
};
|
|
387197
|
+
|
|
387052
387198
|
// ../../packages/backend/src/services/dem/rumLedger.ts
|
|
387053
387199
|
var import_crypto16 = require("crypto");
|
|
387054
387200
|
var DEFAULT_LIMIT5 = 5e4;
|
|
@@ -392597,6 +392743,8 @@ function createObservability(deps) {
|
|
|
392597
392743
|
getActual: async () => ""
|
|
392598
392744
|
});
|
|
392599
392745
|
const spanLedger = new SpanLedger({});
|
|
392746
|
+
const llmTrace = new LlmTraceRecorder();
|
|
392747
|
+
llmTrace.setSpanLedger(spanLedger);
|
|
392600
392748
|
const rumLedger = new RumLedger({});
|
|
392601
392749
|
const infraMonitor = new InfraMonitor({});
|
|
392602
392750
|
const etwService = new EtwService({});
|
|
@@ -392737,7 +392885,7 @@ function createObservability(deps) {
|
|
|
392737
392885
|
endpoint: otelEndpoint,
|
|
392738
392886
|
resourceAttributes: { "service.name": "rterm", "service.version": process.env.GYBACKEND_VERSION ?? "dev" }
|
|
392739
392887
|
}) : null;
|
|
392740
|
-
const
|
|
392888
|
+
const buildHostMetricsRegistry = () => {
|
|
392741
392889
|
const series = [];
|
|
392742
392890
|
for (const host of metricsLedger.hosts()) {
|
|
392743
392891
|
const latest = metricsLedger.latest(host);
|
|
@@ -392747,9 +392895,9 @@ function createObservability(deps) {
|
|
|
392747
392895
|
if (typeof v === "number" && Number.isFinite(v)) series.push({ host, metric: `host_${k}`, value: v });
|
|
392748
392896
|
}
|
|
392749
392897
|
}
|
|
392750
|
-
|
|
392751
|
-
return reg.render();
|
|
392898
|
+
return registryFromHostMetrics(series, { prefix: "rterm", helpPrefix: "RTerm host metric" });
|
|
392752
392899
|
};
|
|
392900
|
+
const renderPrometheus = () => buildHostMetricsRegistry().render();
|
|
392753
392901
|
const secretsVault = new SecretsVault({
|
|
392754
392902
|
masterKey: process.env.RTERM_SECRETS_MASTER_KEY,
|
|
392755
392903
|
onAudit: (action, key) => {
|
|
@@ -393094,8 +393242,7 @@ function createObservability(deps) {
|
|
|
393094
393242
|
const intervalMs = Number(process.env.OTEL_EXPORTER_OTLP_INTERVAL_MS ?? 3e4) || 3e4;
|
|
393095
393243
|
const pushOnce = async () => {
|
|
393096
393244
|
try {
|
|
393097
|
-
|
|
393098
|
-
await otelExporter.push(prometheusRegistry);
|
|
393245
|
+
await otelExporter.push(buildHostMetricsRegistry());
|
|
393099
393246
|
} catch {
|
|
393100
393247
|
}
|
|
393101
393248
|
};
|
|
@@ -393105,6 +393252,28 @@ function createObservability(deps) {
|
|
|
393105
393252
|
if (typeof otelPushTimer.unref === "function") otelPushTimer.unref();
|
|
393106
393253
|
void pushOnce();
|
|
393107
393254
|
}
|
|
393255
|
+
if (otelEndpoint) {
|
|
393256
|
+
llmTrace.setOtlpTraceExporter((spans) => {
|
|
393257
|
+
void fetch(otelEndpoint.replace(/\/v1\/metrics$/, "/v1/traces"), {
|
|
393258
|
+
method: "POST",
|
|
393259
|
+
headers: { "content-type": "application/json" },
|
|
393260
|
+
body: JSON.stringify({
|
|
393261
|
+
resourceSpans: [
|
|
393262
|
+
{
|
|
393263
|
+
resource: {
|
|
393264
|
+
attributes: [
|
|
393265
|
+
{ key: "service.name", value: { stringValue: "rterm-agent" } },
|
|
393266
|
+
{ key: "service.version", value: { stringValue: process.env.GYBACKEND_VERSION ?? "dev" } }
|
|
393267
|
+
]
|
|
393268
|
+
},
|
|
393269
|
+
scopeSpans: [{ spans }]
|
|
393270
|
+
}
|
|
393271
|
+
]
|
|
393272
|
+
})
|
|
393273
|
+
}).catch(() => {
|
|
393274
|
+
});
|
|
393275
|
+
});
|
|
393276
|
+
}
|
|
393108
393277
|
const oncallTickTimer = setInterval(() => {
|
|
393109
393278
|
void escalationService.tick().catch(() => {
|
|
393110
393279
|
});
|
|
@@ -393129,6 +393298,7 @@ function createObservability(deps) {
|
|
|
393129
393298
|
anomalyDetector,
|
|
393130
393299
|
earlyWarning,
|
|
393131
393300
|
behaviorLedger,
|
|
393301
|
+
llmTrace,
|
|
393132
393302
|
dagu: { parseDaguYaml, parseDaguWorkflow, daguExecutionPlan },
|
|
393133
393303
|
notify: { slackChannel, teamsChannel, smtpChannel, telegramChannel },
|
|
393134
393304
|
aperf: { service: aperfService, toMetricPoint: aperfSummaryToMetricPoint },
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "neuralos",
|
|
3
|
-
"version": "3.2.
|
|
4
|
-
"description": "Headless AI-native backend for RTerm / neuralOS — v3.2.
|
|
3
|
+
"version": "3.2.14",
|
|
4
|
+
"description": "Headless AI-native backend for RTerm / neuralOS — v3.2.14: OTLP metrics push fixed (was always empty) + OpenLLMetry-style LLM tracing (every model call becomes an APM span with gen_ai attributes; optional forwarding to Jaeger/Tempo/Datadog). Chat console fixes from 3.2.12 included. 11 plugins, 55 plugin tools, parallel tool execution, captureStatus.",
|
|
5
5
|
"main": "bin/gybackend.cjs",
|
|
6
6
|
"bin": { "gybackend": "bin/gybackend.cjs" },
|
|
7
7
|
"license": "MIT",
|