@cartanova/qgrid-ai-sdk 2.1.1 → 2.2.0
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.d.ts +12 -0
- package/dist/index.js +25 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -22,11 +22,23 @@ type QgridOpenAIProviderOptions = {
|
|
|
22
22
|
/** 응답 텍스트의 상세도. */
|
|
23
23
|
textVerbosity?: "low" | "medium" | "high";
|
|
24
24
|
};
|
|
25
|
+
/**
|
|
26
|
+
* codex thread 좌표
|
|
27
|
+
* 멀티턴 대화에서 같은 대화를 같은 codex thread 로 라우팅 → conversation_id 고정 → 캐시 적중
|
|
28
|
+
* provider 내부 threadCoordStore 가 sessionKey 별로 관리
|
|
29
|
+
*/
|
|
30
|
+
|
|
25
31
|
/**
|
|
26
32
|
* {@link QgridOpenAIProviderOptions}
|
|
27
33
|
*/
|
|
28
34
|
type QgridProviderOptions = {
|
|
29
35
|
openai?: QgridOpenAIProviderOptions;
|
|
36
|
+
/**
|
|
37
|
+
* 멀티턴 대화 식별자. 호출자가 자기 도메인 ID(예: 게임 세션 ID) 하나만 넘기면, provider 가
|
|
38
|
+
* 같은 sessionKey 의 thread 좌표를 내부에서 회송해 prompt cache 를 적중시킨다.
|
|
39
|
+
* 좌표는 sessionKey 별로 격리된다.
|
|
40
|
+
*/
|
|
41
|
+
sessionKey?: string;
|
|
30
42
|
};
|
|
31
43
|
type QgridSupportedModel = "openai/gpt-5.5" | "openai/gpt-5.4" | "openai/gpt-5.2" | "openai/gpt-5.4-mini" | "openai/gpt-5.3-codex" | "openai/gpt-5.3-codex-spark" | "anthropic/claude-haiku-4-5" | "anthropic/claude-sonnet-4" | "anthropic/claude-sonnet-4-5" | "anthropic/claude-sonnet-4-6" | "anthropic/claude-sonnet-4-7" | "anthropic/claude-opus-4" | "anthropic/claude-opus-4-1" | "anthropic/claude-opus-4-5" | "anthropic/claude-opus-4-6" | "anthropic/claude-opus-4-7" | "anthropic/claude-opus-4-8";
|
|
32
44
|
type QgridLoggerConfig = {
|
package/dist/index.js
CHANGED
|
@@ -461,6 +461,23 @@ function createQgridLogger(config = {}) {
|
|
|
461
461
|
//#region src/index.ts
|
|
462
462
|
const DEFAULT_SERVER_URL = "http://localhost:44900";
|
|
463
463
|
const DEFAULT_EFFORT = "low";
|
|
464
|
+
const THREAD_COORD_TTL_MS = 10 * 6e4;
|
|
465
|
+
const threadCoordStore = /* @__PURE__ */ new Map();
|
|
466
|
+
function getThreadCoord(sessionKey) {
|
|
467
|
+
const entry = threadCoordStore.get(sessionKey);
|
|
468
|
+
if (!entry) return void 0;
|
|
469
|
+
if (entry.expiresAt <= Date.now()) {
|
|
470
|
+
threadCoordStore.delete(sessionKey);
|
|
471
|
+
return;
|
|
472
|
+
}
|
|
473
|
+
return entry.coord;
|
|
474
|
+
}
|
|
475
|
+
function setThreadCoord(sessionKey, coord) {
|
|
476
|
+
threadCoordStore.set(sessionKey, {
|
|
477
|
+
coord,
|
|
478
|
+
expiresAt: Date.now() + THREAD_COORD_TTL_MS
|
|
479
|
+
});
|
|
480
|
+
}
|
|
464
481
|
function qgrid(modelId, config) {
|
|
465
482
|
const serverUrl = config?.serverUrl ?? process.env.QGRID_URL ?? DEFAULT_SERVER_URL;
|
|
466
483
|
const effort = config?.defaultEffort ?? DEFAULT_EFFORT;
|
|
@@ -478,6 +495,7 @@ function qgrid(modelId, config) {
|
|
|
478
495
|
const effectiveEffort = openaiOpts?.reasoningEffort ?? effort;
|
|
479
496
|
const verbosity = openaiOpts?.textVerbosity ?? openaiOpts?.verbosity;
|
|
480
497
|
const reasoningSummary = openaiOpts?.reasoningSummary;
|
|
498
|
+
const sessionKey = (options.providerOptions?.qgrid)?.sessionKey;
|
|
481
499
|
const rawSchema = options.responseFormat?.type === "json" ? options.responseFormat.schema : void 0;
|
|
482
500
|
const schemaType = rawSchema ? rawSchema.type : void 0;
|
|
483
501
|
if (rawSchema && !hasTools && schemaType !== "object") console.warn(`[qgrid] responseFormat.schema top-level type is "${schemaType ?? "unknown"}". OpenAI structured output requires "object". Falling back to client-side parsing.`);
|
|
@@ -500,6 +518,8 @@ function qgrid(modelId, config) {
|
|
|
500
518
|
clientRun = null;
|
|
501
519
|
}
|
|
502
520
|
}
|
|
521
|
+
const storedCoord = sessionKey ? getThreadCoord(sessionKey) : void 0;
|
|
522
|
+
if (!runContext && storedCoord) runContext = { threadCoord: storedCoord };
|
|
503
523
|
if (!logMode && hasTools) logMode = "run";
|
|
504
524
|
const data = await fetch(`${serverUrl}/api/qgrid/query`, {
|
|
505
525
|
method: "POST",
|
|
@@ -555,6 +575,7 @@ function qgrid(modelId, config) {
|
|
|
555
575
|
pendingToolCallIds: new Set(content.filter((c) => c.type === "tool-call").map((c) => c.toolCallId))
|
|
556
576
|
};
|
|
557
577
|
else clientRun = null;
|
|
578
|
+
if (sessionKey && data.runContext?.threadCoord) setThreadCoord(sessionKey, data.runContext.threadCoord);
|
|
558
579
|
return {
|
|
559
580
|
content,
|
|
560
581
|
finishReason,
|
|
@@ -589,6 +610,7 @@ function qgrid(modelId, config) {
|
|
|
589
610
|
const effectiveEffort = openaiOpts?.reasoningEffort ?? effort;
|
|
590
611
|
const verbosity = openaiOpts?.textVerbosity ?? openaiOpts?.verbosity;
|
|
591
612
|
const reasoningSummary = openaiOpts?.reasoningSummary;
|
|
613
|
+
const sessionKey = (options.providerOptions?.qgrid)?.sessionKey;
|
|
592
614
|
const rawSchema = options.responseFormat?.type === "json" ? options.responseFormat.schema : void 0;
|
|
593
615
|
const jsonSchema = !hasTools && rawSchema && rawSchema.type === "object" ? JSON.stringify(rawSchema) : void 0;
|
|
594
616
|
let runContext;
|
|
@@ -609,6 +631,8 @@ function qgrid(modelId, config) {
|
|
|
609
631
|
clientRun = null;
|
|
610
632
|
}
|
|
611
633
|
}
|
|
634
|
+
const storedCoord = sessionKey ? getThreadCoord(sessionKey) : void 0;
|
|
635
|
+
if (!runContext && storedCoord) runContext = { threadCoord: storedCoord };
|
|
612
636
|
if (!logMode && hasTools) logMode = "run";
|
|
613
637
|
const prepRes = await fetch(`${serverUrl}/api/qgrid/prepareStream`, {
|
|
614
638
|
method: "POST",
|
|
@@ -675,6 +699,7 @@ function qgrid(modelId, config) {
|
|
|
675
699
|
pendingToolCallIds: new Set((done.content ?? []).filter((c) => c.type === "tool-call").map((c) => c.toolCallId))
|
|
676
700
|
};
|
|
677
701
|
else clientRun = null;
|
|
702
|
+
if (sessionKey && done.runContext?.threadCoord) setThreadCoord(sessionKey, done.runContext.threadCoord);
|
|
678
703
|
if (done.content) {
|
|
679
704
|
for (const item of done.content) if (item.type === "text" && !deltaTextEmitted) {
|
|
680
705
|
const tid = `text_${Math.random().toString(36).slice(2, 10)}`;
|