@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.
@@ -143135,7 +143135,7 @@ var require_metadata4 = __commonJS({
143135
143135
  }
143136
143136
  }
143137
143137
  }
143138
- var Metadata2 = class _Metadata {
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 = Metadata2;
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: Metadata2
166977
+ Metadata: Metadata3
166978
166978
  // eslint-disable-next-line @typescript-eslint/no-require-imports
166979
166979
  } = require_src24();
166980
- return new Metadata2();
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 = "fb972b2f8";
221371
- CLI_VERSION = "0.64.0-preview.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 Metadata2 = this.grpc.Metadata;
234394
- const baseMetadata = new Metadata2();
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.some((message) => isResumableMessageRecord(message));
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 = loadedRecord;
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
- const initialMetadata = {
292999
- sessionId: this.sessionId,
293000
- projectHash: this.projectHash,
293001
- startTime: (/* @__PURE__ */ new Date()).toISOString(),
293002
- lastUpdated: (/* @__PURE__ */ new Date()).toISOString(),
293003
- kind: this.kind,
293004
- directories
293005
- };
293006
- this.appendRecord(initialMetadata);
293007
- this.cachedConversation = {
293008
- ...initialMetadata,
293009
- messages: []
293010
- };
293011
- this.rebuildIndexAndWindow([]);
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 messages) {
293095
+ for (const msg of safeMessages) {
293060
293096
  this.indexMessage(msg);
293061
293097
  }
293062
293098
  if (this.cachedConversation) {
293063
- this.cachedConversation.messages = messages.length > MAX_HISTORY_MESSAGES ? messages.slice(-MAX_HISTORY_MESSAGES) : [...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 (!this.conversationFile || !this.cachedConversation) {
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.64.0-preview.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
- return contents.map((content) => {
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
- name: fc.name,
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
- name: fr2.name,
368245
- response: fr2.response,
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 closing model turn when history ends with an unanswered tool
368680
- * response, so the next user message stays a turn of its own.
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
- closeUnansweredToolResponseTurn() {
368825
+ closeUnansweredToolCallsTurn() {
368683
368826
  const turns = this.agentHistory.get();
368684
368827
  const last2 = turns[turns.length - 1];
368685
- if (last2?.content.role !== "user" || !last2.content.parts?.some((part) => !!part.functionResponse)) {
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: randomUUID8(),
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 = contentsToUse;
368815
- const finalContents = stripToolCallIdPrefixes(contentsToUse);
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
- if (!iss) {
380531
- debugLogger.error('OAuth callback rejected: Missing required "iss" parameter when an expected issuer is configured. Possible IdP mix-up attack (RFC 9207).');
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
- debugLogger.debug("\u2713 OAuth callback issuer validated successfully.");
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
- server.close();
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 { Authorization: `Bearer ${this.cachedToken.accessToken}` };
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 { Authorization: `Bearer ${this.cachedToken.accessToken}` };
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(_req, res) {
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
- if (this.authRetryCount >= BaseA2AAuthProvider.MAX_AUTH_RETRIES) {
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
- return this.headers();
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
- throw new FatalCancellationError("Authentication cancelled by user.");
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 callbackServer = startCallbackServer(pkceParams.state, preferredPort, config2.issuer);
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 import_grpc_js, 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;
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
- import_grpc_js = __toESM(require_src24(), 1);
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, import_grpc_js.makeGenericClientConstructor)(A2AServiceService, "a2a.v1.A2AService");
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
  }