@oh-my-pi/pi-ai 12.0.0 → 12.1.1
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oh-my-pi/pi-ai",
|
|
3
|
-
"version": "12.
|
|
3
|
+
"version": "12.1.1",
|
|
4
4
|
"description": "Unified LLM API with automatic model discovery and provider configuration",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.ts",
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"@connectrpc/connect-node": "^2.1.1",
|
|
64
64
|
"@google/genai": "^1.39.0",
|
|
65
65
|
"@mistralai/mistralai": "^1.13.0",
|
|
66
|
-
"@oh-my-pi/pi-utils": "12.
|
|
66
|
+
"@oh-my-pi/pi-utils": "12.1.1",
|
|
67
67
|
"@sinclair/typebox": "^0.34.48",
|
|
68
68
|
"@smithy/node-http-handler": "^4.4.9",
|
|
69
69
|
"ajv": "^8.17.1",
|
|
@@ -82,17 +82,22 @@
|
|
|
82
82
|
"unified",
|
|
83
83
|
"api"
|
|
84
84
|
],
|
|
85
|
-
"author": "
|
|
85
|
+
"author": "Can Bölük",
|
|
86
|
+
"contributors": ["Mario Zechner"],
|
|
86
87
|
"license": "MIT",
|
|
87
88
|
"repository": {
|
|
88
89
|
"type": "git",
|
|
89
90
|
"url": "git+https://github.com/can1357/oh-my-pi.git",
|
|
90
91
|
"directory": "packages/ai"
|
|
91
92
|
},
|
|
92
|
-
"
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
93
|
+
"homepage": "https://github.com/can1357/oh-my-pi",
|
|
94
|
+
"bugs": {
|
|
95
|
+
"url": "https://github.com/can1357/oh-my-pi/issues"
|
|
96
|
+
},
|
|
97
|
+
"engines": {
|
|
98
|
+
"bun": ">=1.3.7"
|
|
99
|
+
},
|
|
100
|
+
"devDependencies": {
|
|
101
|
+
"@types/bun": "^1.3.9"
|
|
102
|
+
}
|
|
98
103
|
}
|
|
@@ -460,12 +460,17 @@ function buildParams(
|
|
|
460
460
|
}
|
|
461
461
|
|
|
462
462
|
if (model.reasoning) {
|
|
463
|
+
// Always request encrypted reasoning content so reasoning items can be
|
|
464
|
+
// replayed in multi-turn conversations when store is false (items aren't
|
|
465
|
+
// persisted server-side, so we must include the full content).
|
|
466
|
+
// See: https://github.com/can1357/oh-my-pi/issues/41
|
|
467
|
+
params.include = ["reasoning.encrypted_content"];
|
|
468
|
+
|
|
463
469
|
if (options?.reasoningEffort || options?.reasoningSummary) {
|
|
464
470
|
params.reasoning = {
|
|
465
471
|
effort: options?.reasoningEffort || "medium",
|
|
466
472
|
summary: options?.reasoningSummary || "auto",
|
|
467
473
|
};
|
|
468
|
-
params.include = ["reasoning.encrypted_content"];
|
|
469
474
|
} else {
|
|
470
475
|
if (model.name.toLowerCase().startsWith("gpt-5")) {
|
|
471
476
|
// Jesus Christ, see https://community.openai.com/t/need-reasoning-false-option-for-gpt-5/1351588/7
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
* Shared utilities for Google Generative AI and Google Cloud Code Assist providers.
|
|
3
3
|
*/
|
|
4
4
|
import { type Content, FinishReason, FunctionCallingConfigMode, type Part } from "@google/genai";
|
|
5
|
+
import type { AnySchema } from "ajv";
|
|
6
|
+
import Ajv2020 from "ajv/dist/2020.js";
|
|
5
7
|
import type { Context, ImageContent, Model, StopReason, TextContent, Tool } from "../types";
|
|
6
8
|
import { sanitizeSurrogates } from "../utils/sanitize-unicode";
|
|
7
9
|
import { transformMessages } from "./transform-messages";
|
|
@@ -257,7 +259,6 @@ const UNSUPPORTED_SCHEMA_FIELDS = new Set([
|
|
|
257
259
|
"$defs",
|
|
258
260
|
"$dynamicRef",
|
|
259
261
|
"$dynamicAnchor",
|
|
260
|
-
"format",
|
|
261
262
|
"examples",
|
|
262
263
|
"prefixItems",
|
|
263
264
|
"unevaluatedProperties",
|
|
@@ -276,65 +277,164 @@ const UNSUPPORTED_SCHEMA_FIELDS = new Set([
|
|
|
276
277
|
"format",
|
|
277
278
|
]);
|
|
278
279
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
280
|
+
interface SanitizeSchemaOptions {
|
|
281
|
+
insideProperties: boolean;
|
|
282
|
+
normalizeTypeArrayToNullable: boolean;
|
|
283
|
+
stripNullableKeyword: boolean;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
type JsonObject = Record<string, unknown>;
|
|
287
|
+
|
|
288
|
+
function isJsonObject(value: unknown): value is JsonObject {
|
|
289
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function areJsonValuesEqual(left: unknown, right: unknown): boolean {
|
|
293
|
+
if (Object.is(left, right)) {
|
|
294
|
+
return true;
|
|
295
|
+
}
|
|
296
|
+
if (Array.isArray(left) || Array.isArray(right)) {
|
|
297
|
+
if (!Array.isArray(left) || !Array.isArray(right) || left.length !== right.length) {
|
|
298
|
+
return false;
|
|
299
|
+
}
|
|
300
|
+
for (let i = 0; i < left.length; i += 1) {
|
|
301
|
+
if (!areJsonValuesEqual(left[i], right[i])) {
|
|
302
|
+
return false;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
return true;
|
|
306
|
+
}
|
|
307
|
+
if (!isJsonObject(left) || !isJsonObject(right)) {
|
|
308
|
+
return false;
|
|
309
|
+
}
|
|
310
|
+
const leftKeys = Object.keys(left);
|
|
311
|
+
const rightKeys = Object.keys(right);
|
|
312
|
+
if (leftKeys.length !== rightKeys.length) {
|
|
313
|
+
return false;
|
|
314
|
+
}
|
|
315
|
+
for (const key of leftKeys) {
|
|
316
|
+
if (!(key in right) || !areJsonValuesEqual(left[key], right[key])) {
|
|
317
|
+
return false;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
return true;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
function mergeCompatibleEnumSchemas(existing: unknown, incoming: unknown): JsonObject | null {
|
|
324
|
+
if (!isJsonObject(existing) || !isJsonObject(incoming)) {
|
|
325
|
+
return null;
|
|
326
|
+
}
|
|
327
|
+
const existingEnum = Array.isArray(existing.enum) ? existing.enum : null;
|
|
328
|
+
const incomingEnum = Array.isArray(incoming.enum) ? incoming.enum : null;
|
|
329
|
+
if (!existingEnum || !incomingEnum) {
|
|
330
|
+
return null;
|
|
331
|
+
}
|
|
332
|
+
if (!areJsonValuesEqual(existing.type, incoming.type)) {
|
|
333
|
+
return null;
|
|
334
|
+
}
|
|
335
|
+
const existingKeys = Object.keys(existing).filter(key => key !== "enum");
|
|
336
|
+
const incomingKeys = Object.keys(incoming).filter(key => key !== "enum");
|
|
337
|
+
if (existingKeys.length !== incomingKeys.length) {
|
|
338
|
+
return null;
|
|
339
|
+
}
|
|
340
|
+
for (const key of existingKeys) {
|
|
341
|
+
if (!(key in incoming) || !areJsonValuesEqual(existing[key], incoming[key])) {
|
|
342
|
+
return null;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
const mergedEnum = [...existingEnum];
|
|
347
|
+
for (const enumValue of incomingEnum) {
|
|
348
|
+
if (!mergedEnum.some(existingValue => Object.is(existingValue, enumValue))) {
|
|
349
|
+
mergedEnum.push(enumValue);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
return {
|
|
353
|
+
...existing,
|
|
354
|
+
enum: mergedEnum,
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
function getAnyOfVariants(schema: unknown): unknown[] {
|
|
359
|
+
if (isJsonObject(schema) && Array.isArray(schema.anyOf)) {
|
|
360
|
+
return schema.anyOf;
|
|
361
|
+
}
|
|
362
|
+
return [schema];
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
function mergePropertySchemas(existing: unknown, incoming: unknown): unknown {
|
|
366
|
+
if (areJsonValuesEqual(existing, incoming)) {
|
|
367
|
+
return existing;
|
|
368
|
+
}
|
|
369
|
+
const mergedEnumSchema = mergeCompatibleEnumSchemas(existing, incoming);
|
|
370
|
+
if (mergedEnumSchema !== null) {
|
|
371
|
+
return mergedEnumSchema;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
const mergedAnyOf = [...getAnyOfVariants(existing)];
|
|
375
|
+
for (const variant of getAnyOfVariants(incoming)) {
|
|
376
|
+
if (!mergedAnyOf.some(existingVariant => areJsonValuesEqual(existingVariant, variant))) {
|
|
377
|
+
mergedAnyOf.push(variant);
|
|
378
|
+
}
|
|
282
379
|
}
|
|
380
|
+
return mergedAnyOf.length === 1 ? mergedAnyOf[0] : { anyOf: mergedAnyOf };
|
|
381
|
+
}
|
|
283
382
|
|
|
383
|
+
function sanitizeSchemaImpl(value: unknown, options: SanitizeSchemaOptions): unknown {
|
|
384
|
+
if (Array.isArray(value)) {
|
|
385
|
+
return value.map(entry => sanitizeSchemaImpl(entry, options));
|
|
386
|
+
}
|
|
284
387
|
if (!value || typeof value !== "object") {
|
|
285
388
|
return value;
|
|
286
389
|
}
|
|
287
|
-
|
|
288
390
|
const obj = value as Record<string, unknown>;
|
|
289
391
|
const result: Record<string, unknown> = {};
|
|
290
|
-
|
|
291
|
-
// Collapse anyOf/oneOf of const values into enum
|
|
292
392
|
for (const combiner of ["anyOf", "oneOf"] as const) {
|
|
293
393
|
if (Array.isArray(obj[combiner])) {
|
|
294
394
|
const variants = obj[combiner] as Record<string, unknown>[];
|
|
295
|
-
|
|
296
|
-
// Check if ALL variants have a const field
|
|
297
395
|
const allHaveConst = variants.every(v => v && typeof v === "object" && "const" in v);
|
|
298
|
-
|
|
299
396
|
if (allHaveConst && variants.length > 0) {
|
|
300
|
-
// Extract all const values into enum
|
|
301
397
|
result.enum = variants.map(v => v.const);
|
|
302
|
-
|
|
303
|
-
// Inherit type from first variant if present
|
|
304
398
|
const firstType = variants[0]?.type;
|
|
305
399
|
if (firstType) {
|
|
306
400
|
result.type = firstType;
|
|
307
401
|
}
|
|
308
|
-
|
|
309
402
|
// Copy description and other top-level fields (not the combiner)
|
|
310
403
|
for (const [key, entry] of Object.entries(obj)) {
|
|
311
404
|
if (key !== combiner && !(key in result)) {
|
|
312
|
-
result[key] = sanitizeSchemaImpl(entry,
|
|
405
|
+
result[key] = sanitizeSchemaImpl(entry, {
|
|
406
|
+
insideProperties: false,
|
|
407
|
+
normalizeTypeArrayToNullable: options.normalizeTypeArrayToNullable,
|
|
408
|
+
stripNullableKeyword: options.stripNullableKeyword,
|
|
409
|
+
});
|
|
313
410
|
}
|
|
314
411
|
}
|
|
315
412
|
return result;
|
|
316
413
|
}
|
|
317
414
|
}
|
|
318
415
|
}
|
|
319
|
-
|
|
320
416
|
// Regular field processing
|
|
321
417
|
let constValue: unknown;
|
|
322
418
|
for (const [key, entry] of Object.entries(obj)) {
|
|
323
419
|
// Only strip unsupported schema keywords when NOT inside "properties" object
|
|
324
420
|
// Inside "properties", keys are property names (e.g., "pattern") not schema keywords
|
|
325
|
-
if (!
|
|
421
|
+
if (!options.insideProperties && UNSUPPORTED_SCHEMA_FIELDS.has(key)) continue;
|
|
422
|
+
if (options.stripNullableKeyword && key === "nullable") continue;
|
|
326
423
|
if (key === "const") {
|
|
327
424
|
constValue = entry;
|
|
328
425
|
continue;
|
|
329
426
|
}
|
|
330
427
|
if (key === "additionalProperties" && entry === false) continue;
|
|
331
428
|
// When key is "properties", child keys are property names, not schema keywords
|
|
332
|
-
result[key] = sanitizeSchemaImpl(entry,
|
|
429
|
+
result[key] = sanitizeSchemaImpl(entry, {
|
|
430
|
+
insideProperties: key === "properties",
|
|
431
|
+
normalizeTypeArrayToNullable: options.normalizeTypeArrayToNullable,
|
|
432
|
+
stripNullableKeyword: options.stripNullableKeyword,
|
|
433
|
+
});
|
|
333
434
|
}
|
|
334
|
-
|
|
335
435
|
// Normalize array-valued "type" (e.g. ["string", "null"]) to a single type + nullable.
|
|
336
436
|
// Google's Schema proto expects type to be a single enum string, not an array.
|
|
337
|
-
if (Array.isArray(result.type)) {
|
|
437
|
+
if (options.normalizeTypeArrayToNullable && Array.isArray(result.type)) {
|
|
338
438
|
const types = result.type as string[];
|
|
339
439
|
const nonNull = types.filter(t => t !== "null");
|
|
340
440
|
if (types.includes("null")) {
|
|
@@ -342,7 +442,6 @@ function sanitizeSchemaImpl(value: unknown, isInsideProperties: boolean): unknow
|
|
|
342
442
|
}
|
|
343
443
|
result.type = nonNull[0] ?? types[0];
|
|
344
444
|
}
|
|
345
|
-
|
|
346
445
|
if (constValue !== undefined) {
|
|
347
446
|
// Convert const to enum, merging with existing enum if present
|
|
348
447
|
const existingEnum = Array.isArray(result.enum) ? result.enum : [];
|
|
@@ -364,9 +463,135 @@ function sanitizeSchemaImpl(value: unknown, isInsideProperties: boolean): unknow
|
|
|
364
463
|
|
|
365
464
|
return result;
|
|
366
465
|
}
|
|
367
|
-
|
|
368
466
|
export function sanitizeSchemaForGoogle(value: unknown): unknown {
|
|
369
|
-
return sanitizeSchemaImpl(value,
|
|
467
|
+
return sanitizeSchemaImpl(value, {
|
|
468
|
+
insideProperties: false,
|
|
469
|
+
normalizeTypeArrayToNullable: true,
|
|
470
|
+
stripNullableKeyword: false,
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
export function sanitizeSchemaForCloudCodeAssistClaude(value: unknown): unknown {
|
|
475
|
+
return sanitizeSchemaImpl(value, {
|
|
476
|
+
insideProperties: false,
|
|
477
|
+
normalizeTypeArrayToNullable: false,
|
|
478
|
+
stripNullableKeyword: true,
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
/**
|
|
483
|
+
* Claude via Cloud Code Assist (`parameters` path) can reject schemas that keep
|
|
484
|
+
* object variant combiners, so flatten object-only unions into one object shape.
|
|
485
|
+
*/
|
|
486
|
+
function mergeObjectCombinerVariants(schema: JsonObject, combiner: "anyOf" | "oneOf"): JsonObject {
|
|
487
|
+
const variantsRaw = schema[combiner];
|
|
488
|
+
if (!Array.isArray(variantsRaw) || variantsRaw.length === 0) {
|
|
489
|
+
return schema;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
const variants: JsonObject[] = [];
|
|
493
|
+
for (const entry of variantsRaw) {
|
|
494
|
+
if (!isJsonObject(entry)) {
|
|
495
|
+
return schema;
|
|
496
|
+
}
|
|
497
|
+
const variantType = entry.type;
|
|
498
|
+
if (variantType !== undefined && variantType !== "object") {
|
|
499
|
+
return schema;
|
|
500
|
+
}
|
|
501
|
+
if (entry.properties !== undefined && !isJsonObject(entry.properties)) {
|
|
502
|
+
return schema;
|
|
503
|
+
}
|
|
504
|
+
variants.push(entry);
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
const mergedProperties: JsonObject = {};
|
|
508
|
+
const ownProperties = isJsonObject(schema.properties) ? schema.properties : {};
|
|
509
|
+
for (const [name, propertySchema] of Object.entries(ownProperties)) {
|
|
510
|
+
mergedProperties[name] = propertySchema;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
for (const variant of variants) {
|
|
514
|
+
const properties = isJsonObject(variant.properties) ? variant.properties : {};
|
|
515
|
+
for (const [name, propertySchema] of Object.entries(properties)) {
|
|
516
|
+
const existingSchema = mergedProperties[name];
|
|
517
|
+
mergedProperties[name] =
|
|
518
|
+
existingSchema === undefined ? propertySchema : mergePropertySchemas(existingSchema, propertySchema);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
const nextSchema: JsonObject = {};
|
|
523
|
+
for (const [key, entry] of Object.entries(schema)) {
|
|
524
|
+
if (key === combiner) continue;
|
|
525
|
+
nextSchema[key] = entry;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
nextSchema.type = "object";
|
|
529
|
+
nextSchema.properties = mergedProperties;
|
|
530
|
+
return nextSchema;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
function normalizeSchemaForCloudCodeAssistClaude(value: unknown): unknown {
|
|
534
|
+
if (Array.isArray(value)) {
|
|
535
|
+
return value.map(entry => normalizeSchemaForCloudCodeAssistClaude(entry));
|
|
536
|
+
}
|
|
537
|
+
if (!isJsonObject(value)) {
|
|
538
|
+
return value;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
const normalized: JsonObject = {};
|
|
542
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
543
|
+
normalized[key] = normalizeSchemaForCloudCodeAssistClaude(entry);
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
const mergedAnyOf = mergeObjectCombinerVariants(normalized, "anyOf");
|
|
547
|
+
return mergeObjectCombinerVariants(mergedAnyOf, "oneOf");
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
let cloudCodeAssistSchemaValidator: Ajv2020 | null = null;
|
|
551
|
+
function getCloudCodeAssistSchemaValidator(): Ajv2020 {
|
|
552
|
+
if (cloudCodeAssistSchemaValidator) {
|
|
553
|
+
return cloudCodeAssistSchemaValidator;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
cloudCodeAssistSchemaValidator = new Ajv2020({
|
|
557
|
+
allErrors: true,
|
|
558
|
+
strict: false,
|
|
559
|
+
validateSchema: true,
|
|
560
|
+
});
|
|
561
|
+
return cloudCodeAssistSchemaValidator;
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
/**
|
|
565
|
+
* Keep validation synchronous in this request path.
|
|
566
|
+
*/
|
|
567
|
+
function isValidCloudCodeAssistClaudeSchema(schema: unknown): boolean {
|
|
568
|
+
try {
|
|
569
|
+
const result = getCloudCodeAssistSchemaValidator().validateSchema(schema as AnySchema);
|
|
570
|
+
return typeof result === "boolean" ? result : false;
|
|
571
|
+
} catch {
|
|
572
|
+
return false;
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
const CLOUD_CODE_ASSIST_CLAUDE_FALLBACK_SCHEMA = {
|
|
577
|
+
type: "object",
|
|
578
|
+
properties: {},
|
|
579
|
+
} as const;
|
|
580
|
+
|
|
581
|
+
/**
|
|
582
|
+
* Prepare schema for Claude on Cloud Code Assist:
|
|
583
|
+
* sanitize -> normalize union objects -> validate -> fallback.
|
|
584
|
+
*
|
|
585
|
+
* Fallback is per-tool and fail-open to avoid rejecting the entire request when
|
|
586
|
+
* one tool schema is invalid.
|
|
587
|
+
*/
|
|
588
|
+
export function prepareSchemaForCloudCodeAssistClaude(value: unknown): unknown {
|
|
589
|
+
const sanitized = sanitizeSchemaForCloudCodeAssistClaude(value);
|
|
590
|
+
const normalized = normalizeSchemaForCloudCodeAssistClaude(sanitized);
|
|
591
|
+
if (isValidCloudCodeAssistClaudeSchema(normalized)) {
|
|
592
|
+
return normalized;
|
|
593
|
+
}
|
|
594
|
+
return CLOUD_CODE_ASSIST_CLAUDE_FALLBACK_SCHEMA;
|
|
370
595
|
}
|
|
371
596
|
|
|
372
597
|
/**
|
|
@@ -384,8 +609,10 @@ export function convertTools(
|
|
|
384
609
|
): { functionDeclarations: Record<string, unknown>[] }[] | undefined {
|
|
385
610
|
if (tools.length === 0) return undefined;
|
|
386
611
|
|
|
387
|
-
|
|
388
|
-
|
|
612
|
+
/**
|
|
613
|
+
* Claude models on Cloud Code Assist need the legacy `parameters` field;
|
|
614
|
+
* the API translates it into Anthropic's `input_schema`.
|
|
615
|
+
*/
|
|
389
616
|
const useParameters = model.id.startsWith("claude-");
|
|
390
617
|
|
|
391
618
|
return [
|
|
@@ -394,7 +621,7 @@ export function convertTools(
|
|
|
394
621
|
name: tool.name,
|
|
395
622
|
description: tool.description,
|
|
396
623
|
...(useParameters
|
|
397
|
-
? { parameters:
|
|
624
|
+
? { parameters: prepareSchemaForCloudCodeAssistClaude(tool.parameters) }
|
|
398
625
|
: { parametersJsonSchema: tool.parameters }),
|
|
399
626
|
})),
|
|
400
627
|
},
|
|
@@ -454,12 +454,17 @@ function buildParams(model: Model<"openai-responses">, context: Context, options
|
|
|
454
454
|
}
|
|
455
455
|
|
|
456
456
|
if (model.reasoning) {
|
|
457
|
+
// Always request encrypted reasoning content so reasoning items can be
|
|
458
|
+
// replayed in multi-turn conversations when store is false (items aren't
|
|
459
|
+
// persisted server-side, so we must include the full content).
|
|
460
|
+
// See: https://github.com/can1357/oh-my-pi/issues/41
|
|
461
|
+
params.include = ["reasoning.encrypted_content"];
|
|
462
|
+
|
|
457
463
|
if (options?.reasoningEffort || options?.reasoningSummary) {
|
|
458
464
|
params.reasoning = {
|
|
459
465
|
effort: options?.reasoningEffort || "medium",
|
|
460
466
|
summary: options?.reasoningSummary || "auto",
|
|
461
467
|
};
|
|
462
|
-
params.include = ["reasoning.encrypted_content"];
|
|
463
468
|
} else {
|
|
464
469
|
if (model.name.startsWith("gpt-5")) {
|
|
465
470
|
// Jesus Christ, see https://community.openai.com/t/need-reasoning-false-option-for-gpt-5/1351588/7
|
package/src/storage.ts
CHANGED
|
@@ -5,9 +5,8 @@
|
|
|
5
5
|
|
|
6
6
|
import { Database, type Statement } from "bun:sqlite";
|
|
7
7
|
import * as fs from "node:fs/promises";
|
|
8
|
-
import * as os from "node:os";
|
|
9
8
|
import * as path from "node:path";
|
|
10
|
-
import {
|
|
9
|
+
import { getAgentDir } from "@oh-my-pi/pi-utils/dirs";
|
|
11
10
|
import type { OAuthCredentials } from "./utils/oauth/types";
|
|
12
11
|
|
|
13
12
|
type AuthCredential = { type: "api_key"; key: string } | ({ type: "oauth" } & OAuthCredentials);
|
|
@@ -21,14 +20,6 @@ type AuthRow = {
|
|
|
21
20
|
updated_at: number;
|
|
22
21
|
};
|
|
23
22
|
|
|
24
|
-
/**
|
|
25
|
-
* Get the agent config directory (e.g., ~/.omp/agent/)
|
|
26
|
-
*/
|
|
27
|
-
function getAgentDir(): string {
|
|
28
|
-
const configDir = $env.PI_CODING_AGENT_DIR || path.join(os.homedir(), ".omp", "agent");
|
|
29
|
-
return configDir;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
23
|
/**
|
|
33
24
|
* Get path to agent.db
|
|
34
25
|
*/
|
|
@@ -7,7 +7,7 @@ import type { OAuthController, OAuthCredentials } from "./types";
|
|
|
7
7
|
|
|
8
8
|
const decode = (s: string) => atob(s);
|
|
9
9
|
const CLIENT_ID = decode("OWQxYzI1MGEtZTYxYi00NGQ5LTg4ZWQtNTk0NGQxOTYyZjVl");
|
|
10
|
-
const AUTHORIZE_URL = "https://
|
|
10
|
+
const AUTHORIZE_URL = "https://claude.ai/oauth/authorize";
|
|
11
11
|
const TOKEN_URL = "https://platform.claude.com/v1/oauth/token";
|
|
12
12
|
const CALLBACK_PORT = 54545;
|
|
13
13
|
const CALLBACK_PATH = "/callback";
|
package/src/utils/oauth/kimi.ts
CHANGED
|
@@ -7,6 +7,7 @@ import * as fs from "node:fs/promises";
|
|
|
7
7
|
import * as os from "node:os";
|
|
8
8
|
import * as path from "node:path";
|
|
9
9
|
import { $env, abortableSleep, isEnoent } from "@oh-my-pi/pi-utils";
|
|
10
|
+
import { getAgentDir } from "@oh-my-pi/pi-utils/dirs";
|
|
10
11
|
import packageJson from "../../../package.json" with { type: "json" };
|
|
11
12
|
import type { OAuthController, OAuthCredentials } from "./types";
|
|
12
13
|
|
|
@@ -36,11 +37,6 @@ interface TokenResponse {
|
|
|
36
37
|
interval?: number;
|
|
37
38
|
}
|
|
38
39
|
|
|
39
|
-
function getAgentDir(): string {
|
|
40
|
-
const configDir = $env.PI_CODING_AGENT_DIR || path.join(os.homedir(), ".omp", "agent");
|
|
41
|
-
return configDir;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
40
|
function resolveOAuthHost(): string {
|
|
45
41
|
return $env.KIMI_CODE_OAUTH_HOST || $env.KIMI_OAUTH_HOST || DEFAULT_OAUTH_HOST;
|
|
46
42
|
}
|