opencodekit 0.18.19 → 0.18.20

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/index.js CHANGED
@@ -20,7 +20,7 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
20
20
 
21
21
  //#endregion
22
22
  //#region package.json
23
- var version = "0.18.19";
23
+ var version = "0.18.20";
24
24
 
25
25
  //#endregion
26
26
  //#region src/utils/license.ts
Binary file
@@ -360,49 +360,66 @@ function swapModelInBody(
360
360
 
361
361
  // Maximum length for item IDs in the OpenAI Responses API
362
362
  const MAX_RESPONSE_API_ID_LENGTH = 64;
363
+ // OpenAI Responses API only allows: letters, numbers, underscores, dashes
364
+ const INVALID_ID_CHARS = /[^a-zA-Z0-9_-]/g;
365
+
366
+ /** Check if an ID contains characters not allowed by the Responses API */
367
+ function hasInvalidIdChars(id: string): boolean {
368
+ // Use a non-global regex for .test() to avoid lastIndex state bug
369
+ return /[^a-zA-Z0-9_-]/.test(id);
370
+ }
371
+
363
372
  /**
364
- * Sanitize an ID to fit within the Responses API 64-char limit.
365
- * GitHub Copilot returns proprietary long IDs (400+ chars) that violate
366
- * the OpenAI spec. We hash them to a deterministic 64-char string.
367
- * Preserves the original prefix (e.g., "fc_", "msg_", "call_") so that
368
- * OpenAI's prefix validation passes.
373
+ * Sanitize an ID for the Responses API.
374
+ * Handles three issues from GitHub Copilot:
375
+ * 1. Invalid characters Copilot IDs contain +, |, /, = (base64-like encoding)
376
+ * 2. Wrong prefix GPT models return "h_" instead of "fc_" for function_call items
377
+ * 3. Excessive length — Copilot returns 400+ char IDs (max is 64)
378
+ *
379
+ * Approach matches anomalyco/opencode: replace invalid chars with "_", preserve prefix,
380
+ * truncate to 64 chars, strip trailing underscores.
369
381
  *
370
382
  * @param id - The original ID to sanitize
371
383
  * @param forcedPrefix - If provided, use this prefix instead of the detected one.
372
- * Used when the original prefix is wrong (e.g., Copilot returns "h_" instead of "fc_").
373
384
  * See: https://github.com/vercel/ai/issues/5171
374
385
  */
375
386
  function sanitizeResponseId(id: string, forcedPrefix?: string): string {
387
+ if (!id) return id;
388
+
376
389
  // Detect the original prefix (e.g., "fc_", "msg_", "call_", "resp_", "h_")
377
390
  const prefixMatch = id.match(/^([a-z]+_)/);
378
391
  const detectedPrefix = prefixMatch ? prefixMatch[1] : "";
379
392
  const prefix = forcedPrefix ?? detectedPrefix;
380
393
 
381
- // If no forced prefix and within length, return as-is
382
- if (!forcedPrefix && (!id || id.length <= MAX_RESPONSE_API_ID_LENGTH)) {
383
- return id;
384
- }
385
-
386
394
  // Strip the original prefix to get the core ID
387
- const coreId = id.slice(detectedPrefix.length);
395
+ const rawCore = id.slice(detectedPrefix.length);
396
+ // Replace invalid characters with underscores (same as anomalyco/opencode)
397
+ const cleanCore = rawCore.replace(INVALID_ID_CHARS, "_").replace(/_+$/g, "");
398
+
399
+ // Check if any sanitization is actually needed
400
+ const needsSanitization = forcedPrefix || hasInvalidIdChars(rawCore) ||
401
+ id.length > MAX_RESPONSE_API_ID_LENGTH;
402
+
403
+ if (!needsSanitization) return id;
388
404
 
389
- // If just a prefix swap and within length, do a simple replacement
390
- if (forcedPrefix && (prefix.length + coreId.length) <= MAX_RESPONSE_API_ID_LENGTH) {
391
- return `${prefix}${coreId}`;
405
+ // If result fits within length and core is non-empty, use cleaned core directly
406
+ if (cleanCore.length > 0 && (prefix.length + cleanCore.length) <= MAX_RESPONSE_API_ID_LENGTH) {
407
+ return `${prefix}${cleanCore}`;
392
408
  }
393
409
 
394
- // Hash the full original ID for deterministic uniqueness
410
+ // Hash the full original ID for deterministic uniqueness when truncating
395
411
  let hash = 0;
396
412
  for (let i = 0; i < id.length; i++) {
397
413
  hash = ((hash << 5) - hash + id.charCodeAt(i)) | 0;
398
414
  }
399
415
  const hashStr = Math.abs(hash).toString(36);
400
- // Take some chars from the core for additional uniqueness
401
416
  const maxMiddleLen =
402
417
  MAX_RESPONSE_API_ID_LENGTH - prefix.length - hashStr.length - 1;
403
- const middle = coreId.slice(0, Math.max(0, maxMiddleLen));
418
+ const middle = cleanCore.slice(0, Math.max(0, maxMiddleLen));
404
419
  // Format: prefix + middle + "_" + hash (ensure total <= 64)
405
- return `${prefix}${middle}_${hashStr}`.slice(0, MAX_RESPONSE_API_ID_LENGTH);
420
+ const result = `${prefix}${middle}_${hashStr}`.slice(0, MAX_RESPONSE_API_ID_LENGTH);
421
+ // Strip trailing underscores from truncation
422
+ return result.replace(/_+$/, "");
406
423
  }
407
424
 
408
425
  /**
@@ -419,16 +436,21 @@ function getExpectedPrefix(item: any): string | null {
419
436
  return null;
420
437
  }
421
438
 
439
+ /** Check if a string ID needs sanitization (invalid chars or too long) */
440
+ function idNeedsSanitization(id: string): boolean {
441
+ return id.length > MAX_RESPONSE_API_ID_LENGTH || hasInvalidIdChars(id);
442
+ }
443
+
422
444
  /**
423
445
  * Sanitize all IDs in a Responses API input array.
424
446
  *
425
- * Handles TWO classes of invalid IDs:
426
- * 1. Wrong prefix — Copilot GPT models return IDs like "h_xxx" instead of "fc_xxx"
427
- * for function_call items. These are short but have the wrong prefix.
428
- * 2. Excessive length — Copilot returns 400+ char IDs that exceed the 64-char limit.
447
+ * Handles THREE classes of invalid IDs:
448
+ * 1. Invalid characters — Copilot IDs contain +, |, /, = (only [a-zA-Z0-9_-] allowed)
449
+ * 2. Wrong prefix Copilot GPT models return IDs like "h_xxx" instead of "fc_xxx"
450
+ * 3. Excessive length — Copilot returns 400+ char IDs that exceed the 64-char limit.
429
451
  *
430
452
  * Uses a two-pass approach:
431
- * - Pass 1: Build an ID remap for all invalid IDs (both prefix and length issues)
453
+ * - Pass 1: Build an ID remap for all invalid IDs
432
454
  * - Pass 2: Apply the remap to both `id` and `call_id` fields consistently,
433
455
  * so function_call_output.call_id stays in sync with function_call.id
434
456
  */
@@ -448,10 +470,10 @@ function sanitizeResponseInputIds(input: any[]): any[] {
448
470
  }
449
471
  }
450
472
 
451
- // Check for excessive length on id
473
+ // Check for invalid chars or excessive length on id
452
474
  if (
453
475
  typeof item.id === "string" &&
454
- item.id.length > MAX_RESPONSE_API_ID_LENGTH &&
476
+ idNeedsSanitization(item.id) &&
455
477
  !idRemap.has(item.id)
456
478
  ) {
457
479
  idRemap.set(item.id, sanitizeResponseId(item.id));
@@ -471,10 +493,10 @@ function sanitizeResponseInputIds(input: any[]): any[] {
471
493
  }
472
494
  }
473
495
 
474
- // Check for excessive length on call_id
496
+ // Check for invalid chars or excessive length on call_id
475
497
  if (
476
498
  typeof item.call_id === "string" &&
477
- item.call_id.length > MAX_RESPONSE_API_ID_LENGTH &&
499
+ idNeedsSanitization(item.call_id) &&
478
500
  !idRemap.has(item.call_id)
479
501
  ) {
480
502
  idRemap.set(item.call_id, sanitizeResponseId(item.call_id));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencodekit",
3
- "version": "0.18.19",
3
+ "version": "0.18.20",
4
4
  "description": "CLI tool for bootstrapping and managing OpenCodeKit projects",
5
5
  "keywords": [
6
6
  "agents",