Skip to content
8 changes: 5 additions & 3 deletions packages/contracts/src/assistantCitations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ import { EnvironmentId, MessageId, NonNegativeInt, ThreadId } from "./baseSchema
export const ASSISTANT_CITATION_MAX_TEXT_LENGTH = 8_000;
export const ASSISTANT_CITATION_MAX_COMMENT_LENGTH = 8_000;
export const ASSISTANT_CITATION_CONTEXT_LENGTH = 32;
// Provider message IDs nest and re-encode their thread and turn IDs, so they outgrow a few hundred characters.
export const ASSISTANT_CITATION_MAX_ID_LENGTH = 4_096;

/** Positions are UTF-16 offsets, not Markdown offsets. */
export const AssistantCitation = Schema.Struct({
version: Schema.Literal(1),
environmentId: EnvironmentId.check(Schema.isMaxLength(512)),
threadId: ThreadId.check(Schema.isMaxLength(512)),
messageId: MessageId.check(Schema.isMaxLength(512)),
environmentId: EnvironmentId.check(Schema.isMaxLength(ASSISTANT_CITATION_MAX_ID_LENGTH)),
threadId: ThreadId.check(Schema.isMaxLength(ASSISTANT_CITATION_MAX_ID_LENGTH)),
messageId: MessageId.check(Schema.isMaxLength(ASSISTANT_CITATION_MAX_ID_LENGTH)),
text: Schema.String.check(
Schema.isNonEmpty(),
Schema.isMaxLength(ASSISTANT_CITATION_MAX_TEXT_LENGTH),
Expand Down
7 changes: 4 additions & 3 deletions packages/shared/src/assistantCitations.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { describe, expect, it } from "vite-plus/test";
import {
ASSISTANT_CITATION_CONTEXT_LENGTH,
ASSISTANT_CITATION_MAX_COMMENT_LENGTH,
ASSISTANT_CITATION_MAX_ID_LENGTH,
ASSISTANT_CITATION_MAX_TEXT_LENGTH,
EnvironmentId,
MessageId,
Expand Down Expand Up @@ -126,9 +127,9 @@ describe("assistant citation references", () => {
it("accepts complete 8k CJK quotes and comments with maximum-sized source selectors", () => {
const largeCitation: AssistantCitation = {
...citation,
environmentId: EnvironmentId.make("環".repeat(512)),
threadId: ThreadId.make("線".repeat(512)),
messageId: MessageId.make("文".repeat(512)),
environmentId: EnvironmentId.make("環".repeat(ASSISTANT_CITATION_MAX_ID_LENGTH)),
threadId: ThreadId.make("線".repeat(ASSISTANT_CITATION_MAX_ID_LENGTH)),
messageId: MessageId.make("文".repeat(ASSISTANT_CITATION_MAX_ID_LENGTH)),
text: "引".repeat(ASSISTANT_CITATION_MAX_TEXT_LENGTH),
comment: "注".repeat(ASSISTANT_CITATION_MAX_COMMENT_LENGTH),
start: Number.MAX_SAFE_INTEGER - ASSISTANT_CITATION_MAX_TEXT_LENGTH,
Expand Down
11 changes: 9 additions & 2 deletions packages/shared/src/assistantCitations.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import {
ASSISTANT_CITATION_CONTEXT_LENGTH,
ASSISTANT_CITATION_MAX_COMMENT_LENGTH,
ASSISTANT_CITATION_MAX_ID_LENGTH,
ASSISTANT_CITATION_MAX_TEXT_LENGTH,
AssistantCitation,
} from "@t3tools/contracts";
Expand All @@ -8,9 +10,14 @@ import * as Schema from "effect/Schema";

const CITATION_PROTOCOL = "t3-citation:";
const CITATION_HREF_PREFIX = `${CITATION_PROTOCOL}//v1/`;
// Percent encoding needs up to nine characters per UTF-16 code unit; 16k covers selectors.
// Percent encoding needs up to nine characters per UTF-16 code unit; 1k covers keys and offsets.
const MAX_CITATION_HREF_LENGTH =
9 * (ASSISTANT_CITATION_MAX_TEXT_LENGTH + ASSISTANT_CITATION_MAX_COMMENT_LENGTH) + 16_000;
9 *
(ASSISTANT_CITATION_MAX_TEXT_LENGTH +
ASSISTANT_CITATION_MAX_COMMENT_LENGTH +
3 * ASSISTANT_CITATION_MAX_ID_LENGTH +
2 * ASSISTANT_CITATION_CONTEXT_LENGTH) +
1_000;
const CITATION_LINK = new RegExp(
String.raw`\[Assistant quote\]\((${CITATION_HREF_PREFIX}[^\s)]{1,${MAX_CITATION_HREF_LENGTH - CITATION_HREF_PREFIX.length}})\)`,
"g",
Expand Down
Loading