@google/gemini-cli-a2a-server 0.64.0-preview.0 → 0.65.0-nightly.20261008.g44d764ee5
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/a2a-server.mjs +398 -89
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
package/dist/a2a-server.mjs
CHANGED
|
@@ -143135,7 +143135,7 @@ var require_metadata4 = __commonJS({
|
|
|
143135
143135
|
}
|
|
143136
143136
|
}
|
|
143137
143137
|
}
|
|
143138
|
-
var
|
|
143138
|
+
var Metadata3 = class _Metadata {
|
|
143139
143139
|
constructor(options = {}) {
|
|
143140
143140
|
this.internalRepr = /* @__PURE__ */ new Map();
|
|
143141
143141
|
this.opaqueData = /* @__PURE__ */ new Map();
|
|
@@ -143327,7 +143327,7 @@ var require_metadata4 = __commonJS({
|
|
|
143327
143327
|
return result2;
|
|
143328
143328
|
}
|
|
143329
143329
|
};
|
|
143330
|
-
exports2.Metadata =
|
|
143330
|
+
exports2.Metadata = Metadata3;
|
|
143331
143331
|
var bufToString = (val) => {
|
|
143332
143332
|
return Buffer.isBuffer(val) ? val.toString("base64") : val;
|
|
143333
143333
|
};
|
|
@@ -166974,10 +166974,10 @@ var require_grpc_exporter_transport = __commonJS({
|
|
|
166974
166974
|
exports2.createSslCredentials = createSslCredentials;
|
|
166975
166975
|
function createEmptyMetadata() {
|
|
166976
166976
|
const {
|
|
166977
|
-
Metadata:
|
|
166977
|
+
Metadata: Metadata3
|
|
166978
166978
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
166979
166979
|
} = require_src24();
|
|
166980
|
-
return new
|
|
166980
|
+
return new Metadata3();
|
|
166981
166981
|
}
|
|
166982
166982
|
exports2.createEmptyMetadata = createEmptyMetadata;
|
|
166983
166983
|
var GrpcExporterTransport = class {
|
|
@@ -221367,8 +221367,8 @@ var GIT_COMMIT_INFO, CLI_VERSION;
|
|
|
221367
221367
|
var init_git_commit = __esm({
|
|
221368
221368
|
"packages/core/dist/src/generated/git-commit.js"() {
|
|
221369
221369
|
"use strict";
|
|
221370
|
-
GIT_COMMIT_INFO = "
|
|
221371
|
-
CLI_VERSION = "0.
|
|
221370
|
+
GIT_COMMIT_INFO = "44d764ee5";
|
|
221371
|
+
CLI_VERSION = "0.65.0-nightly.20261008.g44d764ee5";
|
|
221372
221372
|
}
|
|
221373
221373
|
});
|
|
221374
221374
|
|
|
@@ -234390,8 +234390,8 @@ var require_grpc = __commonJS({
|
|
|
234390
234390
|
return grpcPackage;
|
|
234391
234391
|
}
|
|
234392
234392
|
metadataBuilder(headers) {
|
|
234393
|
-
const
|
|
234394
|
-
const baseMetadata = new
|
|
234393
|
+
const Metadata3 = this.grpc.Metadata;
|
|
234394
|
+
const baseMetadata = new Metadata3();
|
|
234395
234395
|
for (const key in headers) {
|
|
234396
234396
|
const value = headers[key];
|
|
234397
234397
|
if (Array.isArray(value)) {
|
|
@@ -292506,7 +292506,7 @@ function isResumableMessageRecord(message) {
|
|
|
292506
292506
|
return false;
|
|
292507
292507
|
}
|
|
292508
292508
|
function hasResumableConversationContent(messages) {
|
|
292509
|
-
return messages
|
|
292509
|
+
return messages?.some((message) => isResumableMessageRecord(message)) ?? false;
|
|
292510
292510
|
}
|
|
292511
292511
|
function createJsonlRecordAccumulator(options) {
|
|
292512
292512
|
let metadata2 = {};
|
|
@@ -292907,6 +292907,8 @@ var init_chatRecordingService = __esm({
|
|
|
292907
292907
|
queuedThoughts = [];
|
|
292908
292908
|
queuedTokens = null;
|
|
292909
292909
|
context;
|
|
292910
|
+
isResumedSession = false;
|
|
292911
|
+
initializationPromise = null;
|
|
292910
292912
|
messageOrder = [];
|
|
292911
292913
|
messageMetaMap = /* @__PURE__ */ new Map();
|
|
292912
292914
|
toolCallMetaMap = /* @__PURE__ */ new Map();
|
|
@@ -292918,7 +292920,18 @@ var init_chatRecordingService = __esm({
|
|
|
292918
292920
|
this.sessionId = context2.promptId;
|
|
292919
292921
|
this.projectHash = getProjectHash(context2.config.getProjectRoot());
|
|
292920
292922
|
}
|
|
292923
|
+
getIsResumedSession() {
|
|
292924
|
+
return this.isResumedSession;
|
|
292925
|
+
}
|
|
292926
|
+
setIsResumedSession(isResumed) {
|
|
292927
|
+
this.isResumedSession = isResumed;
|
|
292928
|
+
}
|
|
292921
292929
|
async initialize(resumedSessionData, kind) {
|
|
292930
|
+
this.isResumedSession = Boolean(resumedSessionData);
|
|
292931
|
+
this.initializationPromise = this.doInitialize(resumedSessionData, kind);
|
|
292932
|
+
return this.initializationPromise;
|
|
292933
|
+
}
|
|
292934
|
+
async doInitialize(resumedSessionData, kind) {
|
|
292922
292935
|
try {
|
|
292923
292936
|
this.kind = kind;
|
|
292924
292937
|
if (resumedSessionData) {
|
|
@@ -292927,7 +292940,10 @@ var init_chatRecordingService = __esm({
|
|
|
292927
292940
|
this.kind = resumedSessionData.conversation.kind;
|
|
292928
292941
|
const loadedRecord = await loadConversationRecord(this.conversationFile);
|
|
292929
292942
|
if (loadedRecord) {
|
|
292930
|
-
this.cachedConversation =
|
|
292943
|
+
this.cachedConversation = {
|
|
292944
|
+
...loadedRecord,
|
|
292945
|
+
messages: loadedRecord.messages ?? []
|
|
292946
|
+
};
|
|
292931
292947
|
this.projectHash = this.cachedConversation.projectHash;
|
|
292932
292948
|
if (this.conversationFile.endsWith(".json")) {
|
|
292933
292949
|
this.conversationFile = this.conversationFile + "l";
|
|
@@ -292995,20 +293011,39 @@ var init_chatRecordingService = __esm({
|
|
|
292995
293011
|
const directories = this.kind === "subagent" ? [
|
|
292996
293012
|
...this.context.config.getWorkspaceContext()?.getDirectories() ?? []
|
|
292997
293013
|
] : void 0;
|
|
292998
|
-
|
|
292999
|
-
|
|
293000
|
-
|
|
293001
|
-
|
|
293002
|
-
|
|
293003
|
-
|
|
293004
|
-
|
|
293005
|
-
|
|
293006
|
-
|
|
293007
|
-
|
|
293008
|
-
|
|
293009
|
-
|
|
293010
|
-
|
|
293011
|
-
|
|
293014
|
+
let fileAlreadyExisted = false;
|
|
293015
|
+
if (fs36.existsSync(this.conversationFile)) {
|
|
293016
|
+
fileAlreadyExisted = true;
|
|
293017
|
+
const loadedRecord = await loadConversationRecord(this.conversationFile);
|
|
293018
|
+
if (loadedRecord) {
|
|
293019
|
+
this.cachedConversation = {
|
|
293020
|
+
...loadedRecord,
|
|
293021
|
+
messages: loadedRecord.messages ?? []
|
|
293022
|
+
};
|
|
293023
|
+
this.projectHash = this.cachedConversation.projectHash;
|
|
293024
|
+
if (loadedRecord.hasResumableContent || hasResumableConversationContent(this.cachedConversation.messages)) {
|
|
293025
|
+
this.isResumedSession = true;
|
|
293026
|
+
}
|
|
293027
|
+
}
|
|
293028
|
+
}
|
|
293029
|
+
if (!fileAlreadyExisted || !this.cachedConversation) {
|
|
293030
|
+
const initialMetadata = {
|
|
293031
|
+
sessionId: this.sessionId,
|
|
293032
|
+
projectHash: this.projectHash,
|
|
293033
|
+
startTime: (/* @__PURE__ */ new Date()).toISOString(),
|
|
293034
|
+
lastUpdated: (/* @__PURE__ */ new Date()).toISOString(),
|
|
293035
|
+
kind: this.kind,
|
|
293036
|
+
directories
|
|
293037
|
+
};
|
|
293038
|
+
this.appendRecord(initialMetadata);
|
|
293039
|
+
this.cachedConversation = {
|
|
293040
|
+
...initialMetadata,
|
|
293041
|
+
messages: []
|
|
293042
|
+
};
|
|
293043
|
+
this.rebuildIndexAndWindow([]);
|
|
293044
|
+
} else {
|
|
293045
|
+
this.rebuildIndexAndWindow(this.cachedConversation.messages);
|
|
293046
|
+
}
|
|
293012
293047
|
}
|
|
293013
293048
|
this.queuedThoughts = [];
|
|
293014
293049
|
this.queuedTokens = null;
|
|
@@ -293053,14 +293088,15 @@ var init_chatRecordingService = __esm({
|
|
|
293053
293088
|
this.hasEvictedMessages = msgs.length < this.messageOrder.length;
|
|
293054
293089
|
}
|
|
293055
293090
|
rebuildIndexAndWindow(messages) {
|
|
293091
|
+
const safeMessages = messages ?? [];
|
|
293056
293092
|
this.messageOrder = [];
|
|
293057
293093
|
this.messageMetaMap.clear();
|
|
293058
293094
|
this.toolCallMetaMap.clear();
|
|
293059
|
-
for (const msg of
|
|
293095
|
+
for (const msg of safeMessages) {
|
|
293060
293096
|
this.indexMessage(msg);
|
|
293061
293097
|
}
|
|
293062
293098
|
if (this.cachedConversation) {
|
|
293063
|
-
this.cachedConversation.messages =
|
|
293099
|
+
this.cachedConversation.messages = safeMessages.length > MAX_HISTORY_MESSAGES ? safeMessages.slice(-MAX_HISTORY_MESSAGES) : [...safeMessages];
|
|
293064
293100
|
this.hasEvictedMessages = this.cachedConversation.messages.length < this.messageOrder.length;
|
|
293065
293101
|
} else {
|
|
293066
293102
|
this.hasEvictedMessages = false;
|
|
@@ -293367,12 +293403,30 @@ var init_chatRecordingService = __esm({
|
|
|
293367
293403
|
* session with a real user prompt, model response, or tool activity.
|
|
293368
293404
|
*/
|
|
293369
293405
|
async deleteCurrentSessionIfNotResumableAsync() {
|
|
293370
|
-
if (
|
|
293406
|
+
if (this.initializationPromise) {
|
|
293407
|
+
try {
|
|
293408
|
+
await this.initializationPromise;
|
|
293409
|
+
} catch {
|
|
293410
|
+
}
|
|
293411
|
+
}
|
|
293412
|
+
if (this.isResumedSession) {
|
|
293413
|
+
return;
|
|
293414
|
+
}
|
|
293415
|
+
if (!this.conversationFile) {
|
|
293371
293416
|
return;
|
|
293372
293417
|
}
|
|
293373
|
-
if (hasResumableConversationContent(this.cachedConversation.messages) || Array.from(this.messageMetaMap.values()).some((m3) => m3.isResumable)) {
|
|
293418
|
+
if (this.cachedConversation && hasResumableConversationContent(this.cachedConversation.messages ?? []) || Array.from(this.messageMetaMap.values()).some((m3) => m3.isResumable)) {
|
|
293374
293419
|
return;
|
|
293375
293420
|
}
|
|
293421
|
+
if (fs36.existsSync(this.conversationFile)) {
|
|
293422
|
+
try {
|
|
293423
|
+
const fileRecord = await loadConversationRecord(this.conversationFile);
|
|
293424
|
+
if (fileRecord && (fileRecord.hasResumableContent || hasResumableConversationContent(fileRecord.messages ?? []))) {
|
|
293425
|
+
return;
|
|
293426
|
+
}
|
|
293427
|
+
} catch {
|
|
293428
|
+
}
|
|
293429
|
+
}
|
|
293376
293430
|
await this.deleteCurrentSessionAsync();
|
|
293377
293431
|
}
|
|
293378
293432
|
/**
|
|
@@ -295087,6 +295141,8 @@ async function initializeTelemetry(config2, credentials3) {
|
|
|
295087
295141
|
exportIntervalMillis: 3e4
|
|
295088
295142
|
});
|
|
295089
295143
|
} else if (useOtlp) {
|
|
295144
|
+
const otlpHeaders = config2.getTelemetryOtlpHeaders?.() ?? {};
|
|
295145
|
+
const hasHeaders = Object.keys(otlpHeaders).length > 0;
|
|
295090
295146
|
if (otlpProtocol === "http") {
|
|
295091
295147
|
const buildUrl = (path103) => {
|
|
295092
295148
|
const url5 = new URL(parsedEndpoint);
|
|
@@ -295094,30 +295150,52 @@ async function initializeTelemetry(config2, credentials3) {
|
|
|
295094
295150
|
return url5.href;
|
|
295095
295151
|
};
|
|
295096
295152
|
spanExporter = new import_exporter_trace_otlp_http.OTLPTraceExporter({
|
|
295097
|
-
url: buildUrl("v1/traces")
|
|
295153
|
+
url: buildUrl("v1/traces"),
|
|
295154
|
+
headers: hasHeaders ? otlpHeaders : void 0
|
|
295098
295155
|
});
|
|
295099
295156
|
logExporter = new import_exporter_logs_otlp_http.OTLPLogExporter({
|
|
295100
|
-
url: buildUrl("v1/logs")
|
|
295157
|
+
url: buildUrl("v1/logs"),
|
|
295158
|
+
headers: hasHeaders ? otlpHeaders : void 0
|
|
295101
295159
|
});
|
|
295102
295160
|
metricReader = new import_sdk_metrics2.PeriodicExportingMetricReader({
|
|
295103
295161
|
exporter: new import_exporter_metrics_otlp_http.OTLPMetricExporter({
|
|
295104
|
-
url: buildUrl("v1/metrics")
|
|
295162
|
+
url: buildUrl("v1/metrics"),
|
|
295163
|
+
headers: hasHeaders ? otlpHeaders : void 0
|
|
295105
295164
|
}),
|
|
295106
295165
|
exportIntervalMillis: 1e4
|
|
295107
295166
|
});
|
|
295108
295167
|
} else {
|
|
295168
|
+
let metadata2;
|
|
295169
|
+
if (hasHeaders) {
|
|
295170
|
+
const candidateMetadata = new import_grpc_js.Metadata();
|
|
295171
|
+
let validCount = 0;
|
|
295172
|
+
for (const [key, value] of Object.entries(otlpHeaders)) {
|
|
295173
|
+
try {
|
|
295174
|
+
candidateMetadata.set(key, value);
|
|
295175
|
+
validCount++;
|
|
295176
|
+
} catch (error2) {
|
|
295177
|
+
debugLogger.warn(`[Telemetry] Skipping invalid gRPC metadata key "${key}":`, error2);
|
|
295178
|
+
}
|
|
295179
|
+
}
|
|
295180
|
+
if (validCount > 0) {
|
|
295181
|
+
metadata2 = candidateMetadata;
|
|
295182
|
+
}
|
|
295183
|
+
}
|
|
295109
295184
|
spanExporter = new import_exporter_trace_otlp_grpc.OTLPTraceExporter({
|
|
295110
295185
|
url: parsedEndpoint,
|
|
295111
|
-
compression: CompressionAlgorithm.GZIP
|
|
295186
|
+
compression: CompressionAlgorithm.GZIP,
|
|
295187
|
+
...metadata2 && { metadata: metadata2 }
|
|
295112
295188
|
});
|
|
295113
295189
|
logExporter = new import_exporter_logs_otlp_grpc.OTLPLogExporter({
|
|
295114
295190
|
url: parsedEndpoint,
|
|
295115
|
-
compression: CompressionAlgorithm.GZIP
|
|
295191
|
+
compression: CompressionAlgorithm.GZIP,
|
|
295192
|
+
...metadata2 && { metadata: metadata2 }
|
|
295116
295193
|
});
|
|
295117
295194
|
metricReader = new import_sdk_metrics2.PeriodicExportingMetricReader({
|
|
295118
295195
|
exporter: new import_exporter_metrics_otlp_grpc.OTLPMetricExporter({
|
|
295119
295196
|
url: parsedEndpoint,
|
|
295120
|
-
compression: CompressionAlgorithm.GZIP
|
|
295197
|
+
compression: CompressionAlgorithm.GZIP,
|
|
295198
|
+
...metadata2 && { metadata: metadata2 }
|
|
295121
295199
|
}),
|
|
295122
295200
|
exportIntervalMillis: 1e4
|
|
295123
295201
|
});
|
|
@@ -295214,7 +295292,7 @@ async function shutdownTelemetry(config2, fromProcessExit = true) {
|
|
|
295214
295292
|
activeTelemetryEmail = void 0;
|
|
295215
295293
|
}
|
|
295216
295294
|
}
|
|
295217
|
-
var import_exporter_trace_otlp_grpc, import_exporter_logs_otlp_grpc, import_exporter_metrics_otlp_grpc, import_exporter_trace_otlp_http, import_exporter_logs_otlp_http, import_exporter_metrics_otlp_http, import_sdk_node, import_resources, import_sdk_trace_node, import_sdk_logs, import_sdk_metrics2, import_instrumentation_http, DiagLoggerAdapter, sdk, spanProcessor, logRecordProcessor, metricReader, telemetryInitialized, callbackRegistered, authListener, keychainAvailabilityListener, tokenStorageTypeListener, telemetryBuffer, activeTelemetryEmail;
|
|
295295
|
+
var import_exporter_trace_otlp_grpc, import_exporter_logs_otlp_grpc, import_exporter_metrics_otlp_grpc, import_exporter_trace_otlp_http, import_exporter_logs_otlp_http, import_exporter_metrics_otlp_http, import_grpc_js, import_sdk_node, import_resources, import_sdk_trace_node, import_sdk_logs, import_sdk_metrics2, import_instrumentation_http, DiagLoggerAdapter, sdk, spanProcessor, logRecordProcessor, metricReader, telemetryInitialized, callbackRegistered, authListener, keychainAvailabilityListener, tokenStorageTypeListener, telemetryBuffer, activeTelemetryEmail;
|
|
295218
295296
|
var init_sdk = __esm({
|
|
295219
295297
|
"packages/core/dist/src/telemetry/sdk.js"() {
|
|
295220
295298
|
"use strict";
|
|
@@ -295226,6 +295304,7 @@ var init_sdk = __esm({
|
|
|
295226
295304
|
import_exporter_logs_otlp_http = __toESM(require_src34(), 1);
|
|
295227
295305
|
import_exporter_metrics_otlp_http = __toESM(require_src31(), 1);
|
|
295228
295306
|
init_esm3();
|
|
295307
|
+
import_grpc_js = __toESM(require_src24(), 1);
|
|
295229
295308
|
import_sdk_node = __toESM(require_src48(), 1);
|
|
295230
295309
|
init_esm2();
|
|
295231
295310
|
import_resources = __toESM(require_src26(), 1);
|
|
@@ -337592,7 +337671,7 @@ function getVersion() {
|
|
|
337592
337671
|
}
|
|
337593
337672
|
versionPromise = (async () => {
|
|
337594
337673
|
const pkgJson = await getPackageJson(__dirname4);
|
|
337595
|
-
return "0.
|
|
337674
|
+
return "0.65.0-nightly.20261008.g44d764ee5";
|
|
337596
337675
|
})();
|
|
337597
337676
|
return versionPromise;
|
|
337598
337677
|
}
|
|
@@ -338253,7 +338332,10 @@ function classifyValidationRequiredError(googleApiError) {
|
|
|
338253
338332
|
}
|
|
338254
338333
|
}
|
|
338255
338334
|
if (!validationLink) {
|
|
338256
|
-
validationLink = errorInfo.metadata?.["validation_link"];
|
|
338335
|
+
validationLink = errorInfo.metadata?.["validation_link"] ?? errorInfo.metadata?.["validation_url"];
|
|
338336
|
+
}
|
|
338337
|
+
if (!learnMoreUrl) {
|
|
338338
|
+
learnMoreUrl = errorInfo.metadata?.["validation_learn_more_url"];
|
|
338257
338339
|
}
|
|
338258
338340
|
return new ValidationRequiredError(googleApiError.message, googleApiError, validationLink, validationDescription, learnMoreUrl);
|
|
338259
338341
|
}
|
|
@@ -339089,7 +339171,9 @@ async function retryWithBackoff(fn2, options) {
|
|
|
339089
339171
|
const getCurrentMaxAttempts = () => getAvailabilityContext?.()?.policy.maxAttempts ?? maxAttempts;
|
|
339090
339172
|
let attempt = 0;
|
|
339091
339173
|
let capacityAttempts = 0;
|
|
339174
|
+
let validationAttempts = 0;
|
|
339092
339175
|
const MAX_SILENT_CAPACITY_ATTEMPTS = 3;
|
|
339176
|
+
const MAX_VALIDATION_ATTEMPTS = 3;
|
|
339093
339177
|
let currentDelay = initialDelayMs;
|
|
339094
339178
|
const throwIfAborted = () => {
|
|
339095
339179
|
if (signal?.aborted) {
|
|
@@ -339167,7 +339251,8 @@ async function retryWithBackoff(fn2, options) {
|
|
|
339167
339251
|
}
|
|
339168
339252
|
}
|
|
339169
339253
|
if (classifiedError instanceof ValidationRequiredError) {
|
|
339170
|
-
if (onValidationRequired) {
|
|
339254
|
+
if (onValidationRequired && validationAttempts < MAX_VALIDATION_ATTEMPTS) {
|
|
339255
|
+
validationAttempts++;
|
|
339171
339256
|
try {
|
|
339172
339257
|
const intent = await onValidationRequired(classifiedError);
|
|
339173
339258
|
if (intent === "verify") {
|
|
@@ -342310,6 +342395,8 @@ async function _doSetupUser(client, projectId, config2, httpOptions = {}) {
|
|
|
342310
342395
|
pluginType: "GEMINI"
|
|
342311
342396
|
};
|
|
342312
342397
|
const validationHandler = config2.getValidationHandler();
|
|
342398
|
+
const MAX_VALIDATION_ATTEMPTS = 3;
|
|
342399
|
+
let validationAttempts = 0;
|
|
342313
342400
|
let loadRes;
|
|
342314
342401
|
while (true) {
|
|
342315
342402
|
loadRes = await caServer.loadCodeAssist({
|
|
@@ -342323,7 +342410,8 @@ async function _doSetupUser(client, projectId, config2, httpOptions = {}) {
|
|
|
342323
342410
|
validateLoadCodeAssistResponse(loadRes);
|
|
342324
342411
|
break;
|
|
342325
342412
|
} catch (e3) {
|
|
342326
|
-
if (e3 instanceof ValidationRequiredError && validationHandler) {
|
|
342413
|
+
if (e3 instanceof ValidationRequiredError && validationHandler && validationAttempts < MAX_VALIDATION_ATTEMPTS) {
|
|
342414
|
+
validationAttempts++;
|
|
342327
342415
|
const intent = await validationHandler(e3.validationLink, e3.validationDescription);
|
|
342328
342416
|
if (intent === "verify") {
|
|
342329
342417
|
continue;
|
|
@@ -368074,6 +368162,9 @@ function scrubPart(part) {
|
|
|
368074
368162
|
if (part.functionResponse.id) {
|
|
368075
368163
|
scrubbedResp["id"] = part.functionResponse.id;
|
|
368076
368164
|
}
|
|
368165
|
+
if ("parts" in part.functionResponse && Array.isArray(part.functionResponse.parts)) {
|
|
368166
|
+
scrubbedResp["parts"] = part.functionResponse.parts.map(scrubPart);
|
|
368167
|
+
}
|
|
368077
368168
|
scrubbed["functionResponse"] = scrubbedResp;
|
|
368078
368169
|
}
|
|
368079
368170
|
if ("fileData" in part) {
|
|
@@ -368221,8 +368312,41 @@ function isSchemaDepthError(errorMessage) {
|
|
|
368221
368312
|
function isInvalidArgumentError(errorMessage) {
|
|
368222
368313
|
return errorMessage.includes("Request contains an invalid argument");
|
|
368223
368314
|
}
|
|
368315
|
+
function isEmptyTextPart(part) {
|
|
368316
|
+
if (part.text !== "") {
|
|
368317
|
+
return false;
|
|
368318
|
+
}
|
|
368319
|
+
return !Object.keys(part).some((key) => key !== "text" && key !== "thought" && key !== "callIndex");
|
|
368320
|
+
}
|
|
368321
|
+
function hasNonEmptyParts(content) {
|
|
368322
|
+
return (content.parts ?? []).some((part) => !isEmptyTextPart(part));
|
|
368323
|
+
}
|
|
368324
|
+
function buildInterruptedToolResponseParts(parts2) {
|
|
368325
|
+
return parts2.filter((part) => !!part?.functionCall).map((part) => ({
|
|
368326
|
+
functionResponse: {
|
|
368327
|
+
name: part.functionCall.name?.trim() || "generic_tool",
|
|
368328
|
+
id: part.functionCall.id,
|
|
368329
|
+
response: { error: INTERRUPTED_TOOL_RESPONSE_ERROR }
|
|
368330
|
+
}
|
|
368331
|
+
}));
|
|
368332
|
+
}
|
|
368333
|
+
function ensureTerminalUserTurn(contents) {
|
|
368334
|
+
const last2 = contents.at(-1);
|
|
368335
|
+
if (last2?.role === "user" && hasNonEmptyParts(last2)) {
|
|
368336
|
+
return contents;
|
|
368337
|
+
}
|
|
368338
|
+
if (last2?.role === "user") {
|
|
368339
|
+
return [
|
|
368340
|
+
...contents.slice(0, -1),
|
|
368341
|
+
{ ...last2, parts: [{ text: CONTINUE_PROMPT_TEXT }] }
|
|
368342
|
+
];
|
|
368343
|
+
}
|
|
368344
|
+
const missingResponses = buildInterruptedToolResponseParts(last2?.parts ?? []);
|
|
368345
|
+
const parts2 = missingResponses.length > 0 ? missingResponses : [{ text: CONTINUE_PROMPT_TEXT }];
|
|
368346
|
+
return [...contents, { role: "user", parts: parts2 }];
|
|
368347
|
+
}
|
|
368224
368348
|
function stripToolCallIdPrefixes(contents) {
|
|
368225
|
-
|
|
368349
|
+
const stripped = contents.map((content) => {
|
|
368226
368350
|
const parts2 = (content.parts || []).map((part) => {
|
|
368227
368351
|
const newPart = { ...part };
|
|
368228
368352
|
if (newPart.functionCall) {
|
|
@@ -368230,8 +368354,7 @@ function stripToolCallIdPrefixes(contents) {
|
|
|
368230
368354
|
const name3 = fc.name?.trim() || "generic_tool";
|
|
368231
368355
|
if (fc.id && fc.id.startsWith(`${name3}__`)) {
|
|
368232
368356
|
newPart.functionCall = {
|
|
368233
|
-
|
|
368234
|
-
args: fc.args,
|
|
368357
|
+
...fc,
|
|
368235
368358
|
id: fc.id.substring(name3.length + 2)
|
|
368236
368359
|
};
|
|
368237
368360
|
}
|
|
@@ -368241,8 +368364,9 @@ function stripToolCallIdPrefixes(contents) {
|
|
|
368241
368364
|
const name3 = fr2.name?.trim() || "generic_tool";
|
|
368242
368365
|
if (fr2.id && fr2.id.startsWith(`${name3}__`)) {
|
|
368243
368366
|
newPart.functionResponse = {
|
|
368244
|
-
|
|
368245
|
-
|
|
368367
|
+
// History parts are plain JSON objects, not class instances.
|
|
368368
|
+
// eslint-disable-next-line @typescript-eslint/no-misused-spread
|
|
368369
|
+
...fr2,
|
|
368246
368370
|
id: fr2.id.substring(name3.length + 2)
|
|
368247
368371
|
};
|
|
368248
368372
|
}
|
|
@@ -368252,18 +368376,30 @@ function stripToolCallIdPrefixes(contents) {
|
|
|
368252
368376
|
delete newPart.text;
|
|
368253
368377
|
}
|
|
368254
368378
|
return newPart;
|
|
368255
|
-
}).filter((part) =>
|
|
368256
|
-
const hasOtherKeys = Object.keys(part).some((key) => key !== "text" && key !== "thought" && key !== "callIndex");
|
|
368257
|
-
if (part.text !== void 0 && part.text === "" && !hasOtherKeys) {
|
|
368258
|
-
return false;
|
|
368259
|
-
}
|
|
368260
|
-
return true;
|
|
368261
|
-
});
|
|
368379
|
+
}).filter((part) => !isEmptyTextPart(part));
|
|
368262
368380
|
return {
|
|
368263
368381
|
...content,
|
|
368264
368382
|
parts: parts2
|
|
368265
368383
|
};
|
|
368266
|
-
});
|
|
368384
|
+
}).filter((content) => content.parts.length > 0);
|
|
368385
|
+
return coalesceConsecutiveContents(stripped);
|
|
368386
|
+
}
|
|
368387
|
+
function coalesceConsecutiveContents(contents) {
|
|
368388
|
+
const result2 = [];
|
|
368389
|
+
for (const item of contents) {
|
|
368390
|
+
const lastIdx = result2.length - 1;
|
|
368391
|
+
const last2 = result2[lastIdx];
|
|
368392
|
+
if (last2 && last2.role && last2.role === item.role) {
|
|
368393
|
+
const hasParts = last2.parts || item.parts;
|
|
368394
|
+
result2[lastIdx] = {
|
|
368395
|
+
...last2,
|
|
368396
|
+
parts: hasParts ? [...last2.parts || [], ...item.parts || []] : void 0
|
|
368397
|
+
};
|
|
368398
|
+
} else {
|
|
368399
|
+
result2.push({ ...item });
|
|
368400
|
+
}
|
|
368401
|
+
}
|
|
368402
|
+
return result2;
|
|
368267
368403
|
}
|
|
368268
368404
|
function coalesceConsecutiveRoles(history) {
|
|
368269
368405
|
const result2 = [];
|
|
@@ -368318,7 +368454,7 @@ function stripThoughts2(history) {
|
|
|
368318
368454
|
};
|
|
368319
368455
|
}).filter((turn) => !turn.content.parts || turn.content.parts.length > 0);
|
|
368320
368456
|
}
|
|
368321
|
-
var StreamEventType, MID_STREAM_RETRY_OPTIONS, SYNTHETIC_THOUGHT_SIGNATURE2, INTERRUPTED_RESPONSE_PLACEHOLDER, THINKING_ONLY_NUDGE_MESSAGE, NO_RESPONSE_TEXT_NUDGE_MESSAGE, InvalidStreamError, AgentExecutionStoppedError, AgentExecutionBlockedError, GeminiChat;
|
|
368457
|
+
var StreamEventType, MID_STREAM_RETRY_OPTIONS, SYNTHETIC_THOUGHT_SIGNATURE2, INTERRUPTED_RESPONSE_PLACEHOLDER, INTERRUPTED_TOOL_RESPONSE_ERROR, CONTINUE_PROMPT_TEXT, THINKING_ONLY_NUDGE_MESSAGE, NO_RESPONSE_TEXT_NUDGE_MESSAGE, InvalidStreamError, AgentExecutionStoppedError, AgentExecutionBlockedError, GeminiChat;
|
|
368322
368458
|
var init_geminiChat = __esm({
|
|
368323
368459
|
"packages/core/dist/src/core/geminiChat.js"() {
|
|
368324
368460
|
"use strict";
|
|
@@ -368341,6 +368477,7 @@ var init_geminiChat = __esm({
|
|
|
368341
368477
|
init_tokenCalculation();
|
|
368342
368478
|
init_policyHelpers();
|
|
368343
368479
|
init_events();
|
|
368480
|
+
init_debugLogger();
|
|
368344
368481
|
(function(StreamEventType2) {
|
|
368345
368482
|
StreamEventType2["CHUNK"] = "chunk";
|
|
368346
368483
|
StreamEventType2["RETRY"] = "retry";
|
|
@@ -368355,6 +368492,8 @@ var init_geminiChat = __esm({
|
|
|
368355
368492
|
};
|
|
368356
368493
|
SYNTHETIC_THOUGHT_SIGNATURE2 = "skip_thought_signature_validator";
|
|
368357
368494
|
INTERRUPTED_RESPONSE_PLACEHOLDER = "[The previous response was interrupted before it completed.]";
|
|
368495
|
+
INTERRUPTED_TOOL_RESPONSE_ERROR = "Response was lost or interrupted.";
|
|
368496
|
+
CONTINUE_PROMPT_TEXT = "Please continue.";
|
|
368358
368497
|
THINKING_ONLY_NUDGE_MESSAGE = "[System: You previously generated thoughts but failed to provide a final user-facing response. Please ensure you provide your final answer or call a tool now.]";
|
|
368359
368498
|
NO_RESPONSE_TEXT_NUDGE_MESSAGE = "[System: You previously returned an empty response with no text or thoughts. Please ensure you provide your final answer or call a tool now.]";
|
|
368360
368499
|
InvalidStreamError = class extends Error {
|
|
@@ -368486,6 +368625,7 @@ var init_geminiChat = __esm({
|
|
|
368486
368625
|
let userContent = createUserContent(message);
|
|
368487
368626
|
const isOriginalFunctionResponse = isFunctionResponse(userContent);
|
|
368488
368627
|
if (!isOriginalFunctionResponse) {
|
|
368628
|
+
this.closeUnansweredToolCallsTurn();
|
|
368489
368629
|
this.closeUnansweredToolResponseTurn();
|
|
368490
368630
|
}
|
|
368491
368631
|
const { model } = this.context.config.modelConfigService.getResolvedConfig(modelConfigKey);
|
|
@@ -368512,7 +368652,7 @@ var init_geminiChat = __esm({
|
|
|
368512
368652
|
} else {
|
|
368513
368653
|
const history = this.agentHistory.get();
|
|
368514
368654
|
const lastTurn = history[history.length - 1];
|
|
368515
|
-
if (!lastTurn || partListUnionToString(lastTurn.content.parts || []) !== userMessageContent) {
|
|
368655
|
+
if (!lastTurn || lastTurn.content.role !== "user" || partListUnionToString(lastTurn.content.parts || []) !== userMessageContent) {
|
|
368516
368656
|
const id = this.chatRecordingService.recordMessage({
|
|
368517
368657
|
model,
|
|
368518
368658
|
type: "user",
|
|
@@ -368560,11 +368700,12 @@ var init_geminiChat = __esm({
|
|
|
368560
368700
|
} else {
|
|
368561
368701
|
const history = this.agentHistory.get();
|
|
368562
368702
|
const lastTurn = history[history.length - 1];
|
|
368563
|
-
if (!lastTurn || partListUnionToString(lastTurn.content.parts || []) !== partListUnionToString(userContent.parts || [])) {
|
|
368703
|
+
if (!lastTurn || lastTurn.content.role !== "user" || partListUnionToString(lastTurn.content.parts || []) !== partListUnionToString(userContent.parts || [])) {
|
|
368564
368704
|
this.agentHistory.push({ id, content: userContent });
|
|
368565
368705
|
}
|
|
368566
368706
|
}
|
|
368567
368707
|
}
|
|
368708
|
+
this.replaceEmptyTrailingUserTurn();
|
|
368568
368709
|
const requestHistory = this.getHistoryTurns(true);
|
|
368569
368710
|
const streamWithRetries = async function* () {
|
|
368570
368711
|
let isSuccess = false;
|
|
@@ -368676,23 +368817,77 @@ var init_geminiChat = __esm({
|
|
|
368676
368817
|
return streamWithRetries.call(this);
|
|
368677
368818
|
}
|
|
368678
368819
|
/**
|
|
368679
|
-
* Appends a
|
|
368680
|
-
*
|
|
368820
|
+
* Appends a dedicated synthetic user turn with matching functionResponse
|
|
368821
|
+
* parts when history ends with an unclosed model functionCall. The
|
|
368822
|
+
* subsequent user prompt is then recorded as a clean turn of its own (after
|
|
368823
|
+
* `closeUnansweredToolResponseTurn` adds the closing model turn).
|
|
368681
368824
|
*/
|
|
368682
|
-
|
|
368825
|
+
closeUnansweredToolCallsTurn() {
|
|
368683
368826
|
const turns = this.agentHistory.get();
|
|
368684
368827
|
const last2 = turns[turns.length - 1];
|
|
368685
|
-
if (last2?.content.role !== "
|
|
368828
|
+
if (last2?.content.role !== "model") {
|
|
368829
|
+
return;
|
|
368830
|
+
}
|
|
368831
|
+
const missingResponses = buildInterruptedToolResponseParts(last2.content.parts ?? []);
|
|
368832
|
+
if (missingResponses.length === 0) {
|
|
368686
368833
|
return;
|
|
368687
368834
|
}
|
|
368835
|
+
const id = this.chatRecordingService.recordSyntheticMessage("user", missingResponses);
|
|
368688
368836
|
this.agentHistory.push({
|
|
368689
|
-
id
|
|
368690
|
-
content: {
|
|
368691
|
-
role: "model",
|
|
368692
|
-
parts: [{ text: INTERRUPTED_RESPONSE_PLACEHOLDER }]
|
|
368693
|
-
}
|
|
368837
|
+
id,
|
|
368838
|
+
content: { role: "user", parts: missingResponses }
|
|
368694
368839
|
});
|
|
368695
368840
|
}
|
|
368841
|
+
/**
|
|
368842
|
+
* Replaces the parts of a trailing user turn that carries no content (e.g.
|
|
368843
|
+
* only empty text parts) with a continuation prompt, keeping the in-memory
|
|
368844
|
+
* history and the session log in sync. Runs once per send so that the
|
|
368845
|
+
* persisted history never keeps an empty user turn between model turns.
|
|
368846
|
+
*/
|
|
368847
|
+
replaceEmptyTrailingUserTurn() {
|
|
368848
|
+
const turns = this.agentHistory.get();
|
|
368849
|
+
const last2 = turns[turns.length - 1];
|
|
368850
|
+
if (last2?.content.role !== "user" || hasNonEmptyParts(last2.content)) {
|
|
368851
|
+
return;
|
|
368852
|
+
}
|
|
368853
|
+
this.agentHistory.set([
|
|
368854
|
+
...turns.slice(0, -1),
|
|
368855
|
+
{
|
|
368856
|
+
id: last2.id,
|
|
368857
|
+
content: { ...last2.content, parts: [{ text: CONTINUE_PROMPT_TEXT }] }
|
|
368858
|
+
}
|
|
368859
|
+
]);
|
|
368860
|
+
this.chatRecordingService.updateMessagesFromHistory(this.agentHistory.get());
|
|
368861
|
+
}
|
|
368862
|
+
/**
|
|
368863
|
+
* Appends a closing model turn when history ends with an unanswered tool
|
|
368864
|
+
* response, so the next user message stays a turn of its own.
|
|
368865
|
+
*/
|
|
368866
|
+
closeUnansweredToolResponseTurn() {
|
|
368867
|
+
const turns = this.agentHistory.get();
|
|
368868
|
+
let targetTurn = turns[turns.length - 1];
|
|
368869
|
+
let hadEmptyTrailingModelTurn = false;
|
|
368870
|
+
if (targetTurn?.content.role === "model" && (!targetTurn.content.parts || targetTurn.content.parts.length === 0)) {
|
|
368871
|
+
hadEmptyTrailingModelTurn = true;
|
|
368872
|
+
targetTurn = turns[turns.length - 2];
|
|
368873
|
+
}
|
|
368874
|
+
if (targetTurn?.content.role !== "user" || !targetTurn.content.parts?.some((part) => !!part.functionResponse)) {
|
|
368875
|
+
return;
|
|
368876
|
+
}
|
|
368877
|
+
if (hadEmptyTrailingModelTurn) {
|
|
368878
|
+
const lastTurn = turns[turns.length - 1];
|
|
368879
|
+
lastTurn.content.parts = [{ text: INTERRUPTED_RESPONSE_PLACEHOLDER }];
|
|
368880
|
+
this.chatRecordingService.updateMessagesFromHistory(turns);
|
|
368881
|
+
} else {
|
|
368882
|
+
this.agentHistory.push({
|
|
368883
|
+
id: randomUUID8(),
|
|
368884
|
+
content: {
|
|
368885
|
+
role: "model",
|
|
368886
|
+
parts: [{ text: INTERRUPTED_RESPONSE_PLACEHOLDER }]
|
|
368887
|
+
}
|
|
368888
|
+
});
|
|
368889
|
+
}
|
|
368890
|
+
}
|
|
368696
368891
|
extractBinaryInjections(parts2) {
|
|
368697
368892
|
const binaryParts = [];
|
|
368698
368893
|
if (parts2) {
|
|
@@ -368809,10 +369004,14 @@ var init_geminiChat = __esm({
|
|
|
368809
369004
|
if (this.onModelChanged) {
|
|
368810
369005
|
this.tools = await this.onModelChanged(modelToUse);
|
|
368811
369006
|
}
|
|
369007
|
+
const normalizedContents = ensureTerminalUserTurn(contentsToUse);
|
|
369008
|
+
if (normalizedContents !== contentsToUse) {
|
|
369009
|
+
debugLogger.warn("Final contents do not end with a valid user turn. Normalizing contents to satisfy Gemini API invariant.");
|
|
369010
|
+
}
|
|
368812
369011
|
lastModelToUse = modelToUse;
|
|
368813
369012
|
lastConfig = config2;
|
|
368814
|
-
lastContentsToUse =
|
|
368815
|
-
const finalContents = stripToolCallIdPrefixes(
|
|
369013
|
+
lastContentsToUse = normalizedContents;
|
|
369014
|
+
const finalContents = stripToolCallIdPrefixes(normalizedContents);
|
|
368816
369015
|
return this.context.config.getContentGenerator().generateContentStream({
|
|
368817
369016
|
model: modelToUse,
|
|
368818
369017
|
contents: finalContents,
|
|
@@ -368910,6 +369109,25 @@ var init_geminiChat = __esm({
|
|
|
368910
369109
|
}
|
|
368911
369110
|
ensureStableToolIds(this.agentHistory.get());
|
|
368912
369111
|
}
|
|
369112
|
+
/**
|
|
369113
|
+
* Removes the trailing model turn when it holds function calls that were
|
|
369114
|
+
* never answered (e.g. every call in the batch was declined). Earlier
|
|
369115
|
+
* completed tool rounds and the originating user prompt are kept, and the
|
|
369116
|
+
* durable IDs of the remaining turns are preserved.
|
|
369117
|
+
*
|
|
369118
|
+
* @returns true when a turn was removed.
|
|
369119
|
+
*/
|
|
369120
|
+
discardTrailingUnansweredToolCallTurn() {
|
|
369121
|
+
const turns = this.agentHistory.get();
|
|
369122
|
+
const last2 = turns[turns.length - 1];
|
|
369123
|
+
if (last2?.content.role !== "model" || !last2.content.parts?.some((part) => !!part.functionCall)) {
|
|
369124
|
+
return false;
|
|
369125
|
+
}
|
|
369126
|
+
this.agentHistory.rollback(turns.length - 1);
|
|
369127
|
+
this.lastPromptTokenCount = estimateTokenCountSync(this.agentHistory.flatMap((c2) => c2.content.parts || []));
|
|
369128
|
+
this.chatRecordingService.updateMessagesFromHistory(this.agentHistory.get());
|
|
369129
|
+
return true;
|
|
369130
|
+
}
|
|
368913
369131
|
setHistory(history) {
|
|
368914
369132
|
const wrappedHistory = history.map((item) => {
|
|
368915
369133
|
if ("id" in item && "content" in item) {
|
|
@@ -376673,7 +376891,13 @@ var init_oauth_utils = __esm({
|
|
|
376673
376891
|
issuer: metadata2.issuer,
|
|
376674
376892
|
tokenUrl: metadata2.token_endpoint,
|
|
376675
376893
|
scopes: metadata2.scopes_supported || [],
|
|
376676
|
-
registrationUrl: metadata2.registration_endpoint
|
|
376894
|
+
registrationUrl: metadata2.registration_endpoint,
|
|
376895
|
+
// RFC 9207 Section 3: the flag defaults to false when omitted. Discovered
|
|
376896
|
+
// configurations therefore always carry an explicit boolean, which lets
|
|
376897
|
+
// the callback policy distinguish them from an explicitly configured issuer.
|
|
376898
|
+
// Only a literal boolean `true` enables the flag, so loosely typed values
|
|
376899
|
+
// returned by some servers (e.g. "false" or "0") are not coerced to true.
|
|
376900
|
+
authorizationResponseIssParameterSupported: metadata2.authorization_response_iss_parameter_supported === true
|
|
376677
376901
|
};
|
|
376678
376902
|
}
|
|
376679
376903
|
/**
|
|
@@ -380473,7 +380697,7 @@ function areIssuersEqual(issuerA, issuerB) {
|
|
|
380473
380697
|
}
|
|
380474
380698
|
return normA === normB;
|
|
380475
380699
|
}
|
|
380476
|
-
function startCallbackServer(expectedState, port, expectedIssuer) {
|
|
380700
|
+
function startCallbackServer(expectedState, port, expectedIssuer, requireIssInResponse) {
|
|
380477
380701
|
let portResolve;
|
|
380478
380702
|
let portReject;
|
|
380479
380703
|
const portPromise = new Promise((resolve23, reject) => {
|
|
@@ -380481,6 +380705,13 @@ function startCallbackServer(expectedState, port, expectedIssuer) {
|
|
|
380481
380705
|
portReject = reject;
|
|
380482
380706
|
});
|
|
380483
380707
|
let timeoutId;
|
|
380708
|
+
const abortController = new AbortController();
|
|
380709
|
+
const clearCallbackTimeout = () => {
|
|
380710
|
+
if (timeoutId !== void 0) {
|
|
380711
|
+
clearTimeout(timeoutId);
|
|
380712
|
+
timeoutId = void 0;
|
|
380713
|
+
}
|
|
380714
|
+
};
|
|
380484
380715
|
const responsePromise = new Promise((resolve23, reject) => {
|
|
380485
380716
|
let serverPort;
|
|
380486
380717
|
const server = http6.createServer(async (req, res) => {
|
|
@@ -380508,6 +380739,7 @@ function startCallbackServer(expectedState, port, expectedIssuer) {
|
|
|
380508
380739
|
</body>
|
|
380509
380740
|
</html>
|
|
380510
380741
|
`);
|
|
380742
|
+
clearCallbackTimeout();
|
|
380511
380743
|
server.close();
|
|
380512
380744
|
reject(new Error(`OAuth error: ${error2}`));
|
|
380513
380745
|
return;
|
|
@@ -380522,13 +380754,15 @@ function startCallbackServer(expectedState, port, expectedIssuer) {
|
|
|
380522
380754
|
debugLogger.error(`OAuth callback state mismatch: received state "${state}", expected "${expectedState}". Possible CSRF attack.`);
|
|
380523
380755
|
res.writeHead(400);
|
|
380524
380756
|
res.end("Invalid state parameter");
|
|
380757
|
+
clearCallbackTimeout();
|
|
380525
380758
|
server.close();
|
|
380526
380759
|
reject(new Error("State mismatch - possible CSRF attack"));
|
|
380527
380760
|
return;
|
|
380528
380761
|
}
|
|
380529
380762
|
if (expectedIssuer) {
|
|
380530
|
-
|
|
380531
|
-
|
|
380763
|
+
const requireIss = requireIssInResponse ?? true;
|
|
380764
|
+
if (requireIss && !iss) {
|
|
380765
|
+
debugLogger.error('OAuth callback rejected: Missing required "iss" parameter for the expected authorization server (RFC 9207).');
|
|
380532
380766
|
res.writeHead(400, { "Content-Type": "text/html" });
|
|
380533
380767
|
res.end(`
|
|
380534
380768
|
<html>
|
|
@@ -380543,7 +380777,7 @@ function startCallbackServer(expectedState, port, expectedIssuer) {
|
|
|
380543
380777
|
reject(new Error('Missing "iss" parameter in authorization response per RFC 9207'));
|
|
380544
380778
|
return;
|
|
380545
380779
|
}
|
|
380546
|
-
if (!areIssuersEqual(iss, expectedIssuer)) {
|
|
380780
|
+
if (iss && !areIssuersEqual(iss, expectedIssuer)) {
|
|
380547
380781
|
debugLogger.error("OAuth callback rejected: Issuer mismatch between authorization response and expected authorization server. Possible IdP mix-up attack (RFC 9207).");
|
|
380548
380782
|
res.writeHead(400, { "Content-Type": "text/html" });
|
|
380549
380783
|
res.end(`
|
|
@@ -380559,7 +380793,9 @@ function startCallbackServer(expectedState, port, expectedIssuer) {
|
|
|
380559
380793
|
reject(new Error("Issuer mismatch in authorization response - possible OAuth mix-up attack"));
|
|
380560
380794
|
return;
|
|
380561
380795
|
}
|
|
380562
|
-
|
|
380796
|
+
if (iss) {
|
|
380797
|
+
debugLogger.debug("\u2713 OAuth callback issuer validated successfully.");
|
|
380798
|
+
}
|
|
380563
380799
|
} else if (iss) {
|
|
380564
380800
|
debugLogger.debug('OAuth callback received "iss" parameter (no expected issuer was configured).');
|
|
380565
380801
|
}
|
|
@@ -380573,14 +380809,17 @@ function startCallbackServer(expectedState, port, expectedIssuer) {
|
|
|
380573
380809
|
</body>
|
|
380574
380810
|
</html>
|
|
380575
380811
|
`);
|
|
380812
|
+
clearCallbackTimeout();
|
|
380576
380813
|
server.close();
|
|
380577
380814
|
resolve23({ code, state, iss });
|
|
380578
380815
|
} catch (error2) {
|
|
380816
|
+
clearCallbackTimeout();
|
|
380579
380817
|
server.close();
|
|
380580
380818
|
reject(error2);
|
|
380581
380819
|
}
|
|
380582
380820
|
});
|
|
380583
380821
|
server.on("error", (error2) => {
|
|
380822
|
+
clearCallbackTimeout();
|
|
380584
380823
|
portReject(error2);
|
|
380585
380824
|
reject(error2);
|
|
380586
380825
|
});
|
|
@@ -380604,23 +380843,31 @@ function startCallbackServer(expectedState, port, expectedIssuer) {
|
|
|
380604
380843
|
debugLogger.log(`OAuth callback server listening on port ${serverPort}`);
|
|
380605
380844
|
portResolve(serverPort);
|
|
380606
380845
|
});
|
|
380607
|
-
const abortController = new AbortController();
|
|
380608
380846
|
timeoutId = setTimeout(() => {
|
|
380609
380847
|
abortController.abort(new Error("OAuth callback timeout"));
|
|
380610
380848
|
}, 5 * 60 * 1e3);
|
|
380611
380849
|
timeoutId.unref();
|
|
380612
380850
|
const onAbort = () => {
|
|
380613
|
-
|
|
380851
|
+
clearCallbackTimeout();
|
|
380852
|
+
if (server.listening) {
|
|
380853
|
+
server.close();
|
|
380854
|
+
}
|
|
380614
380855
|
reject(abortController.signal.reason);
|
|
380615
380856
|
};
|
|
380616
380857
|
abortController.signal.addEventListener("abort", onAbort, { once: true });
|
|
380617
380858
|
server.on("close", () => {
|
|
380859
|
+
clearCallbackTimeout();
|
|
380618
380860
|
abortController.signal.removeEventListener("abort", onAbort);
|
|
380619
380861
|
});
|
|
380620
380862
|
});
|
|
380621
380863
|
return {
|
|
380622
380864
|
port: portPromise,
|
|
380623
|
-
response: responsePromise
|
|
380865
|
+
response: responsePromise,
|
|
380866
|
+
cancel: (reason) => {
|
|
380867
|
+
if (!abortController.signal.aborted) {
|
|
380868
|
+
abortController.abort(reason ?? new Error("OAuth callback cancelled"));
|
|
380869
|
+
}
|
|
380870
|
+
}
|
|
380624
380871
|
};
|
|
380625
380872
|
}
|
|
380626
380873
|
function getPortFromUrl(urlString) {
|
|
@@ -380829,6 +381076,7 @@ var init_oauth2_provider = __esm({
|
|
|
380829
381076
|
type = "oauth2";
|
|
380830
381077
|
tokenStorage;
|
|
380831
381078
|
cachedToken = null;
|
|
381079
|
+
pendingAuthPromise = null;
|
|
380832
381080
|
/** Resolved OAuth URLs — may come from config or agent card. */
|
|
380833
381081
|
authorizationUrl;
|
|
380834
381082
|
tokenUrl;
|
|
@@ -380860,12 +381108,26 @@ var init_oauth2_provider = __esm({
|
|
|
380860
381108
|
}
|
|
380861
381109
|
/**
|
|
380862
381110
|
* Return an Authorization header with a valid Bearer token.
|
|
380863
|
-
* Refreshes or triggers interactive auth as needed.
|
|
381111
|
+
* Refreshes or triggers interactive auth as needed, deduplicating concurrent requests.
|
|
380864
381112
|
*/
|
|
380865
381113
|
async headers() {
|
|
380866
381114
|
if (this.cachedToken && !this.tokenStorage.isTokenExpired(this.cachedToken)) {
|
|
381115
|
+
this.authRetryCount = 0;
|
|
380867
381116
|
return { Authorization: `Bearer ${this.cachedToken.accessToken}` };
|
|
380868
381117
|
}
|
|
381118
|
+
if (!this.pendingAuthPromise) {
|
|
381119
|
+
this.pendingAuthPromise = this.acquireToken().finally(() => {
|
|
381120
|
+
this.pendingAuthPromise = null;
|
|
381121
|
+
});
|
|
381122
|
+
}
|
|
381123
|
+
const token2 = await this.pendingAuthPromise;
|
|
381124
|
+
this.authRetryCount = 0;
|
|
381125
|
+
return { Authorization: `Bearer ${token2.accessToken}` };
|
|
381126
|
+
}
|
|
381127
|
+
/**
|
|
381128
|
+
* Refresh an expired token or run interactive browser-based authentication.
|
|
381129
|
+
*/
|
|
381130
|
+
async acquireToken() {
|
|
380869
381131
|
if (this.cachedToken?.refreshToken && this.tokenUrl && this.config.client_id) {
|
|
380870
381132
|
try {
|
|
380871
381133
|
const refreshed = await refreshAccessToken({
|
|
@@ -380875,31 +381137,50 @@ var init_oauth2_provider = __esm({
|
|
|
380875
381137
|
}, this.cachedToken.refreshToken, this.tokenUrl);
|
|
380876
381138
|
this.cachedToken = this.toOAuthToken(refreshed, this.cachedToken.refreshToken);
|
|
380877
381139
|
await this.persistToken();
|
|
380878
|
-
return
|
|
381140
|
+
return this.cachedToken;
|
|
380879
381141
|
} catch (error2) {
|
|
380880
381142
|
debugLogger.debug(`[OAuth2AuthProvider] Refresh failed, falling back to interactive flow: ${getErrorMessage(error2)}`);
|
|
381143
|
+
this.cachedToken = null;
|
|
380881
381144
|
await this.tokenStorage.deleteCredentials(this.agentName);
|
|
380882
381145
|
}
|
|
380883
381146
|
}
|
|
380884
381147
|
this.cachedToken = await this.authenticateInteractively();
|
|
380885
|
-
return
|
|
381148
|
+
return this.cachedToken;
|
|
381149
|
+
}
|
|
381150
|
+
/**
|
|
381151
|
+
* Return the maximum number of consecutive authentication retries allowed.
|
|
381152
|
+
*/
|
|
381153
|
+
getMaxAuthRetries() {
|
|
381154
|
+
return BaseA2AAuthProvider.MAX_AUTH_RETRIES;
|
|
380886
381155
|
}
|
|
380887
381156
|
/**
|
|
380888
381157
|
* On 401/403, clear the cached token and re-authenticate (up to MAX_AUTH_RETRIES).
|
|
380889
381158
|
*/
|
|
380890
|
-
async shouldRetryWithHeaders(
|
|
381159
|
+
async shouldRetryWithHeaders(req, res) {
|
|
380891
381160
|
if (res.status !== 401 && res.status !== 403) {
|
|
380892
381161
|
this.authRetryCount = 0;
|
|
380893
381162
|
return void 0;
|
|
380894
381163
|
}
|
|
380895
|
-
|
|
381164
|
+
const reqHeaders = new Headers(req.headers);
|
|
381165
|
+
const reqToken = reqHeaders.get("Authorization")?.split(" ")[1];
|
|
381166
|
+
if (reqToken && (!this.cachedToken || reqToken !== this.cachedToken.accessToken)) {
|
|
381167
|
+
debugLogger.debug("[OAuth2AuthProvider] Token already cleared or updated by another request, retrying with new token");
|
|
381168
|
+
const retryCount = this.authRetryCount;
|
|
381169
|
+
const headers2 = await this.headers();
|
|
381170
|
+
this.authRetryCount = Math.max(this.authRetryCount, retryCount);
|
|
381171
|
+
return headers2;
|
|
381172
|
+
}
|
|
381173
|
+
if (this.authRetryCount >= this.getMaxAuthRetries()) {
|
|
380896
381174
|
return void 0;
|
|
380897
381175
|
}
|
|
380898
|
-
this.authRetryCount
|
|
381176
|
+
const nextRetryCount = this.authRetryCount + 1;
|
|
381177
|
+
this.authRetryCount = nextRetryCount;
|
|
380899
381178
|
debugLogger.debug("[OAuth2AuthProvider] Auth failure, clearing token and re-authenticating");
|
|
380900
381179
|
this.cachedToken = null;
|
|
380901
381180
|
await this.tokenStorage.deleteCredentials(this.agentName);
|
|
380902
|
-
|
|
381181
|
+
const headers = await this.headers();
|
|
381182
|
+
this.authRetryCount = nextRetryCount;
|
|
381183
|
+
return headers;
|
|
380903
381184
|
}
|
|
380904
381185
|
// ---------------------------------------------------------------------------
|
|
380905
381186
|
// Private helpers
|
|
@@ -380967,7 +381248,11 @@ var init_oauth2_provider = __esm({
|
|
|
380967
381248
|
);
|
|
380968
381249
|
const consent = await getConsentForOauth(`Authentication required for A2A agent: '${this.agentName}'.`);
|
|
380969
381250
|
if (!consent) {
|
|
380970
|
-
|
|
381251
|
+
const cancelError = new FatalCancellationError("Authentication cancelled by user.");
|
|
381252
|
+
callbackServer.response.catch(() => {
|
|
381253
|
+
});
|
|
381254
|
+
callbackServer.cancel?.(cancelError);
|
|
381255
|
+
throw cancelError;
|
|
380971
381256
|
}
|
|
380972
381257
|
coreEvents.emitFeedback("info", `\u2192 Opening your browser for OAuth sign-in...
|
|
380973
381258
|
|
|
@@ -387642,6 +387927,21 @@ var init_client3 = __esm({
|
|
|
387642
387927
|
this.updateTelemetryTokenCount();
|
|
387643
387928
|
this.forceFullIdeContext = true;
|
|
387644
387929
|
}
|
|
387930
|
+
/**
|
|
387931
|
+
* Removes the trailing model turn when it only holds unanswered function
|
|
387932
|
+
* calls. See {@link GeminiChat.discardTrailingUnansweredToolCallTurn}.
|
|
387933
|
+
* Returns false without side effects when the chat is not initialized.
|
|
387934
|
+
*/
|
|
387935
|
+
discardTrailingUnansweredToolCallTurn() {
|
|
387936
|
+
if (!this.isInitialized()) {
|
|
387937
|
+
return false;
|
|
387938
|
+
}
|
|
387939
|
+
const removed = this.getChat().discardTrailingUnansweredToolCallTurn();
|
|
387940
|
+
if (removed) {
|
|
387941
|
+
this.updateTelemetryTokenCount();
|
|
387942
|
+
}
|
|
387943
|
+
return removed;
|
|
387944
|
+
}
|
|
387645
387945
|
lastUsedModelId;
|
|
387646
387946
|
async setTools(modelId) {
|
|
387647
387947
|
if (!this.chat) {
|
|
@@ -410196,6 +410496,7 @@ var init_oauth_provider = __esm({
|
|
|
410196
410496
|
issuer: discoveredConfig.issuer,
|
|
410197
410497
|
tokenUrl: discoveredConfig.tokenUrl,
|
|
410198
410498
|
scopes: config2.scopes || discoveredConfig.scopes || [],
|
|
410499
|
+
authorizationResponseIssParameterSupported: config2.authorizationResponseIssParameterSupported ?? discoveredConfig.authorizationResponseIssParameterSupported,
|
|
410199
410500
|
// Preserve existing client credentials
|
|
410200
410501
|
clientId: config2.clientId,
|
|
410201
410502
|
clientSecret: config2.clientSecret
|
|
@@ -410219,6 +410520,7 @@ var init_oauth_provider = __esm({
|
|
|
410219
410520
|
issuer: discoveredConfig.issuer,
|
|
410220
410521
|
scopes: config2.scopes || discoveredConfig.scopes || [],
|
|
410221
410522
|
registrationUrl: discoveredConfig.registrationUrl,
|
|
410523
|
+
authorizationResponseIssParameterSupported: config2.authorizationResponseIssParameterSupported ?? discoveredConfig.authorizationResponseIssParameterSupported,
|
|
410222
410524
|
// Preserve existing client credentials
|
|
410223
410525
|
clientId: config2.clientId,
|
|
410224
410526
|
clientSecret: config2.clientSecret
|
|
@@ -410231,7 +410533,8 @@ var init_oauth_provider = __esm({
|
|
|
410231
410533
|
const pkceParams = generatePKCEParams();
|
|
410232
410534
|
const preferredPort = getPortFromUrl(config2.redirectUri);
|
|
410233
410535
|
debugLogger.debug(`Starting callback server for "${serverName}" (expected issuer: ${config2.issuer || "none"})...`);
|
|
410234
|
-
const
|
|
410536
|
+
const requireIssInResponse = config2.authorizationResponseIssParameterSupported ?? Boolean(config2.issuer);
|
|
410537
|
+
const callbackServer = startCallbackServer(pkceParams.state, preferredPort, config2.issuer, requireIssInResponse);
|
|
410235
410538
|
const redirectPort = await callbackServer.port;
|
|
410236
410539
|
debugLogger.debug(`Callback server listening on port ${redirectPort}`);
|
|
410237
410540
|
if (!config2.clientId) {
|
|
@@ -410628,7 +410931,8 @@ async function handleAutomaticOAuth(mcpServerName, mcpServerConfig, wwwAuthentic
|
|
|
410628
410931
|
authorizationUrl: oauthConfig.authorizationUrl,
|
|
410629
410932
|
issuer: oauthConfig.issuer,
|
|
410630
410933
|
tokenUrl: oauthConfig.tokenUrl,
|
|
410631
|
-
scopes: oauthConfig.scopes || []
|
|
410934
|
+
scopes: oauthConfig.scopes || [],
|
|
410935
|
+
authorizationResponseIssParameterSupported: mcpServerConfig.oauth?.authorizationResponseIssParameterSupported ?? oauthConfig.authorizationResponseIssParameterSupported
|
|
410632
410936
|
};
|
|
410633
410937
|
debugLogger.log(`Starting OAuth authentication for server '${mcpServerName}'...`);
|
|
410634
410938
|
const authProvider = new MCPOAuthProvider(new MCPOAuthTokenStorage());
|
|
@@ -411044,7 +411348,8 @@ async function connectToMcpServer(clientVersion, mcpServerName, mcpServerConfig,
|
|
|
411044
411348
|
authorizationUrl: oauthConfig.authorizationUrl,
|
|
411045
411349
|
issuer: oauthConfig.issuer,
|
|
411046
411350
|
tokenUrl: oauthConfig.tokenUrl,
|
|
411047
|
-
scopes: oauthConfig.scopes || []
|
|
411351
|
+
scopes: oauthConfig.scopes || [],
|
|
411352
|
+
authorizationResponseIssParameterSupported: mcpServerConfig.oauth?.authorizationResponseIssParameterSupported ?? oauthConfig.authorizationResponseIssParameterSupported
|
|
411048
411353
|
};
|
|
411049
411354
|
const authServerUrl = mcpServerConfig.httpUrl || mcpServerConfig.url;
|
|
411050
411355
|
debugLogger.log(`Starting OAuth authentication for server '${mcpServerName}'...`);
|
|
@@ -413257,11 +413562,11 @@ function fromTimestamp(t3) {
|
|
|
413257
413562
|
millis += (t3.nanos || 0) / 1e6;
|
|
413258
413563
|
return new globalThis.Date(millis).toISOString();
|
|
413259
413564
|
}
|
|
413260
|
-
var
|
|
413565
|
+
var import_grpc_js2, Empty, Struct, Struct_FieldsEntry, Value, ListValue, Timestamp, SendMessageConfiguration2, Task3, TaskStatus3, Part2, FilePart2, DataPart2, Message2, Artifact2, TaskStatusUpdateEvent2, TaskArtifactUpdateEvent2, PushNotificationConfig2, AuthenticationInfo2, AgentInterface2, AgentCard3, AgentCard_SecuritySchemesEntry, AgentProvider2, AgentCapabilities2, AgentExtension2, AgentSkill2, AgentCardSignature2, TaskPushNotificationConfig3, StringList2, Security2, Security_SchemesEntry, SecurityScheme2, APIKeySecurityScheme2, HTTPAuthSecurityScheme2, OAuth2SecurityScheme2, OpenIdConnectSecurityScheme2, MutualTlsSecurityScheme2, OAuthFlows2, AuthorizationCodeOAuthFlow2, AuthorizationCodeOAuthFlow_ScopesEntry, ClientCredentialsOAuthFlow2, ClientCredentialsOAuthFlow_ScopesEntry, ImplicitOAuthFlow2, ImplicitOAuthFlow_ScopesEntry, PasswordOAuthFlow2, PasswordOAuthFlow_ScopesEntry, SendMessageRequest3, GetTaskRequest, CancelTaskRequest, GetTaskPushNotificationConfigRequest, DeleteTaskPushNotificationConfigRequest, CreateTaskPushNotificationConfigRequest, TaskSubscriptionRequest, ListTaskPushNotificationConfigRequest, GetAgentCardRequest, SendMessageResponse3, StreamResponse3, ListTaskPushNotificationConfigResponse3, A2AServiceService, A2AServiceClient;
|
|
413261
413566
|
var init_chunk_QQCCX2KH = __esm({
|
|
413262
413567
|
"packages/core/node_modules/@a2a-js/sdk/dist/chunk-QQCCX2KH.js"() {
|
|
413263
413568
|
init_wire();
|
|
413264
|
-
|
|
413569
|
+
import_grpc_js2 = __toESM(require_src24(), 1);
|
|
413265
413570
|
init_wire();
|
|
413266
413571
|
init_wire();
|
|
413267
413572
|
init_wire();
|
|
@@ -416371,7 +416676,7 @@ var init_chunk_QQCCX2KH = __esm({
|
|
|
416371
416676
|
responseDeserialize: (value) => Empty.decode(value)
|
|
416372
416677
|
}
|
|
416373
416678
|
};
|
|
416374
|
-
A2AServiceClient = (0,
|
|
416679
|
+
A2AServiceClient = (0, import_grpc_js2.makeGenericClientConstructor)(A2AServiceService, "a2a.v1.A2AService");
|
|
416375
416680
|
}
|
|
416376
416681
|
});
|
|
416377
416682
|
|
|
@@ -417357,6 +417662,7 @@ var init_config4 = __esm({
|
|
|
417357
417662
|
target: params.telemetry?.target ?? DEFAULT_TELEMETRY_TARGET,
|
|
417358
417663
|
otlpEndpoint: params.telemetry?.otlpEndpoint ?? DEFAULT_OTLP_ENDPOINT,
|
|
417359
417664
|
otlpProtocol: params.telemetry?.otlpProtocol,
|
|
417665
|
+
otlpHeaders: params.telemetry?.otlpHeaders,
|
|
417360
417666
|
logPrompts: params.telemetry?.logPrompts ?? true,
|
|
417361
417667
|
outfile: params.telemetry?.outfile,
|
|
417362
417668
|
useCollector: params.telemetry?.useCollector,
|
|
@@ -418615,6 +418921,9 @@ ${sections.join("\n")}
|
|
|
418615
418921
|
getTelemetryOtlpProtocol() {
|
|
418616
418922
|
return this.telemetrySettings.otlpProtocol ?? "grpc";
|
|
418617
418923
|
}
|
|
418924
|
+
getTelemetryOtlpHeaders() {
|
|
418925
|
+
return this.telemetrySettings.otlpHeaders ?? {};
|
|
418926
|
+
}
|
|
418618
418927
|
getTelemetryTarget() {
|
|
418619
418928
|
return this.telemetrySettings.target ?? DEFAULT_TELEMETRY_TARGET;
|
|
418620
418929
|
}
|