@intelligo-dev/chat 1.0.0-beta.13
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/LICENSE +201 -0
- package/NOTICE +6 -0
- package/README.md +116 -0
- package/dist/artifact-writer.d.ts +45 -0
- package/dist/artifact-writer.d.ts.map +1 -0
- package/dist/artifact-writer.js +77 -0
- package/dist/artifact-writer.js.map +1 -0
- package/dist/attachments.d.ts +56 -0
- package/dist/attachments.d.ts.map +1 -0
- package/dist/attachments.js +204 -0
- package/dist/attachments.js.map +1 -0
- package/dist/body.d.ts +72 -0
- package/dist/body.d.ts.map +1 -0
- package/dist/body.js +174 -0
- package/dist/body.js.map +1 -0
- package/dist/client.d.ts +65 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +61 -0
- package/dist/client.js.map +1 -0
- package/dist/config.d.ts +322 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +11 -0
- package/dist/config.js.map +1 -0
- package/dist/errors.d.ts +23 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +41 -0
- package/dist/errors.js.map +1 -0
- package/dist/feedback.d.ts +22 -0
- package/dist/feedback.d.ts.map +1 -0
- package/dist/feedback.js +46 -0
- package/dist/feedback.js.map +1 -0
- package/dist/generation.d.ts +104 -0
- package/dist/generation.d.ts.map +1 -0
- package/dist/generation.js +85 -0
- package/dist/generation.js.map +1 -0
- package/dist/handler.d.ts +30 -0
- package/dist/handler.d.ts.map +1 -0
- package/dist/handler.js +913 -0
- package/dist/handler.js.map +1 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/messages.d.ts +19 -0
- package/dist/messages.d.ts.map +1 -0
- package/dist/messages.js +34 -0
- package/dist/messages.js.map +1 -0
- package/dist/parts.d.ts +117 -0
- package/dist/parts.d.ts.map +1 -0
- package/dist/parts.js +13 -0
- package/dist/parts.js.map +1 -0
- package/dist/quota.d.ts +32 -0
- package/dist/quota.d.ts.map +1 -0
- package/dist/quota.js +81 -0
- package/dist/quota.js.map +1 -0
- package/dist/share.d.ts +24 -0
- package/dist/share.d.ts.map +1 -0
- package/dist/share.js +78 -0
- package/dist/share.js.map +1 -0
- package/dist/testing.d.ts +36 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +82 -0
- package/dist/testing.js.map +1 -0
- package/dist/title.d.ts +7 -0
- package/dist/title.d.ts.map +1 -0
- package/dist/title.js +15 -0
- package/dist/title.js.map +1 -0
- package/dist/usage.d.ts +21 -0
- package/dist/usage.d.ts.map +1 -0
- package/dist/usage.js +35 -0
- package/dist/usage.js.map +1 -0
- package/dist/windowing.d.ts +38 -0
- package/dist/windowing.d.ts.map +1 -0
- package/dist/windowing.js +82 -0
- package/dist/windowing.js.map +1 -0
- package/package.json +78 -0
- package/src/artifact-writer.ts +114 -0
- package/src/attachments.ts +262 -0
- package/src/body.ts +236 -0
- package/src/client.ts +133 -0
- package/src/config.ts +376 -0
- package/src/errors.ts +80 -0
- package/src/feedback.ts +62 -0
- package/src/generation.ts +150 -0
- package/src/handler.ts +1164 -0
- package/src/index.ts +93 -0
- package/src/messages.ts +39 -0
- package/src/parts.ts +143 -0
- package/src/quota.ts +105 -0
- package/src/share.ts +103 -0
- package/src/testing.ts +150 -0
- package/src/title.ts +15 -0
- package/src/usage.ts +46 -0
- package/src/windowing.ts +110 -0
package/dist/testing.js
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A deterministic language model (from `ai/test`) that streams end to end
|
|
3
|
+
* before any provider is configured; the transport's own tests use it too.
|
|
4
|
+
* `modelId` is a parameter, never a literal: the boundary bills whatever id
|
|
5
|
+
* the transport settles with, so it must be registered in the pricing table.
|
|
6
|
+
*/
|
|
7
|
+
import { MockLanguageModelV3, simulateReadableStream } from "ai/test";
|
|
8
|
+
/** The last user message's text, from a provider-level prompt. */
|
|
9
|
+
export function lastUserTextOf(prompt) {
|
|
10
|
+
for (let i = prompt.length - 1; i >= 0; i--) {
|
|
11
|
+
const message = prompt[i];
|
|
12
|
+
if (message?.role !== "user")
|
|
13
|
+
continue;
|
|
14
|
+
const parts = Array.isArray(message.content) ? message.content : [];
|
|
15
|
+
return parts
|
|
16
|
+
.filter((part) => typeof part === "object" &&
|
|
17
|
+
part !== null &&
|
|
18
|
+
part.type === "text")
|
|
19
|
+
.map((part) => part.text)
|
|
20
|
+
.join(" ");
|
|
21
|
+
}
|
|
22
|
+
return "";
|
|
23
|
+
}
|
|
24
|
+
export function createStubLanguageModel(options) {
|
|
25
|
+
const delay = options.chunkDelayInMs ?? 15;
|
|
26
|
+
return new MockLanguageModelV3({
|
|
27
|
+
provider: "stub",
|
|
28
|
+
modelId: options.modelId,
|
|
29
|
+
doStream: async ({ prompt }) => {
|
|
30
|
+
const userText = lastUserTextOf(prompt);
|
|
31
|
+
const reply = await options.reply(userText, prompt);
|
|
32
|
+
const call = options.toolCall
|
|
33
|
+
? await options.toolCall(userText, prompt)
|
|
34
|
+
: null;
|
|
35
|
+
const words = reply.split(" ");
|
|
36
|
+
const chunks = [
|
|
37
|
+
{ type: "stream-start", warnings: [] },
|
|
38
|
+
{ type: "text-start", id: "1" },
|
|
39
|
+
...words.map((word, index) => ({
|
|
40
|
+
type: "text-delta",
|
|
41
|
+
id: "1",
|
|
42
|
+
delta: index === 0 ? word : ` ${word}`,
|
|
43
|
+
})),
|
|
44
|
+
{ type: "text-end", id: "1" },
|
|
45
|
+
...(call
|
|
46
|
+
? [
|
|
47
|
+
{
|
|
48
|
+
type: "tool-call",
|
|
49
|
+
toolCallId: `stub-${Date.now()}`,
|
|
50
|
+
toolName: call.toolName,
|
|
51
|
+
input: JSON.stringify(call.input),
|
|
52
|
+
},
|
|
53
|
+
]
|
|
54
|
+
: []),
|
|
55
|
+
{
|
|
56
|
+
type: "finish",
|
|
57
|
+
finishReason: {
|
|
58
|
+
unified: call ? "tool-calls" : "stop",
|
|
59
|
+
raw: undefined,
|
|
60
|
+
},
|
|
61
|
+
usage: {
|
|
62
|
+
inputTokens: {
|
|
63
|
+
total: Math.max(1, Math.ceil(JSON.stringify(prompt).length / 4)),
|
|
64
|
+
noCache: undefined,
|
|
65
|
+
cacheRead: undefined,
|
|
66
|
+
cacheWrite: undefined,
|
|
67
|
+
},
|
|
68
|
+
outputTokens: {
|
|
69
|
+
total: words.length,
|
|
70
|
+
text: words.length,
|
|
71
|
+
reasoning: undefined,
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
];
|
|
76
|
+
return {
|
|
77
|
+
stream: simulateReadableStream({ chunkDelayInMs: delay, chunks }),
|
|
78
|
+
};
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=testing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testing.js","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"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"}
|
package/dist/title.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The default conversation title: the first line of the opening
|
|
3
|
+
* message, truncated to something a sidebar can list.
|
|
4
|
+
*/
|
|
5
|
+
/** First line, trimmed, truncated — enough to tell history rows apart. */
|
|
6
|
+
export declare function truncateTitle(firstUserText: string): string | null;
|
|
7
|
+
//# sourceMappingURL=title.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"title.d.ts","sourceRoot":"","sources":["../src/title.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,0EAA0E;AAC1E,wBAAgB,aAAa,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAMlE"}
|
package/dist/title.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The default conversation title: the first line of the opening
|
|
3
|
+
* message, truncated to something a sidebar can list.
|
|
4
|
+
*/
|
|
5
|
+
const MAX_TITLE_LENGTH = 60;
|
|
6
|
+
/** First line, trimmed, truncated — enough to tell history rows apart. */
|
|
7
|
+
export function truncateTitle(firstUserText) {
|
|
8
|
+
const line = firstUserText.trim().split("\n")[0]?.trim();
|
|
9
|
+
if (!line)
|
|
10
|
+
return null;
|
|
11
|
+
return line.length <= MAX_TITLE_LENGTH
|
|
12
|
+
? line
|
|
13
|
+
: `${line.slice(0, MAX_TITLE_LENGTH - 1).trimEnd()}…`;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=title.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"title.js","sourceRoot":"","sources":["../src/title.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,gBAAgB,GAAG,EAAE,CAAC;AAE5B,0EAA0E;AAC1E,MAAM,UAAU,aAAa,CAAC,aAAqB;IACjD,MAAM,IAAI,GAAG,aAAa,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;IACzD,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IACvB,OAAO,IAAI,CAAC,MAAM,IAAI,gBAAgB;QACpC,CAAC,CAAC,IAAI;QACN,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,gBAAgB,GAAG,CAAC,CAAC,CAAC,OAAO,EAAE,GAAG,CAAC;AAC1D,CAAC"}
|
package/dist/usage.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token usage, in the one shape the execution boundary settles.
|
|
3
|
+
*/
|
|
4
|
+
export type TokenUsage = {
|
|
5
|
+
inputTokens?: number;
|
|
6
|
+
outputTokens?: number;
|
|
7
|
+
totalTokens?: number;
|
|
8
|
+
};
|
|
9
|
+
/** The three fields settlement reads, and nothing else a provider adds. */
|
|
10
|
+
export declare function pickUsage(usage: TokenUsage | undefined): TokenUsage;
|
|
11
|
+
/**
|
|
12
|
+
* Whole-run usage from the steps that completed before an abort. A
|
|
13
|
+
* step still in flight is missed — under-counting by at most one step
|
|
14
|
+
* beats charging nothing and leaving the hold to expire.
|
|
15
|
+
*/
|
|
16
|
+
export declare function sumStepUsage(steps: ReadonlyArray<{
|
|
17
|
+
usage?: TokenUsage;
|
|
18
|
+
}>): TokenUsage;
|
|
19
|
+
/** The sum of two usages; a total a provider omitted is input plus output. */
|
|
20
|
+
export declare function sumUsage(a: TokenUsage, b: TokenUsage): TokenUsage;
|
|
21
|
+
//# sourceMappingURL=usage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usage.d.ts","sourceRoot":"","sources":["../src/usage.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,MAAM,UAAU,GAAG;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,2EAA2E;AAC3E,wBAAgB,SAAS,CAAC,KAAK,EAAE,UAAU,GAAG,SAAS,GAAG,UAAU,CAMnE;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,aAAa,CAAC;IAAE,KAAK,CAAC,EAAE,UAAU,CAAA;CAAE,CAAC,GAC3C,UAAU,CAQZ;AAED,8EAA8E;AAC9E,wBAAgB,QAAQ,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,GAAG,UAAU,CAQjE"}
|
package/dist/usage.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token usage, in the one shape the execution boundary settles.
|
|
3
|
+
*/
|
|
4
|
+
/** The three fields settlement reads, and nothing else a provider adds. */
|
|
5
|
+
export function pickUsage(usage) {
|
|
6
|
+
return {
|
|
7
|
+
inputTokens: usage?.inputTokens,
|
|
8
|
+
outputTokens: usage?.outputTokens,
|
|
9
|
+
totalTokens: usage?.totalTokens,
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Whole-run usage from the steps that completed before an abort. A
|
|
14
|
+
* step still in flight is missed — under-counting by at most one step
|
|
15
|
+
* beats charging nothing and leaving the hold to expire.
|
|
16
|
+
*/
|
|
17
|
+
export function sumStepUsage(steps) {
|
|
18
|
+
let inputTokens = 0;
|
|
19
|
+
let outputTokens = 0;
|
|
20
|
+
for (const step of steps) {
|
|
21
|
+
inputTokens += step.usage?.inputTokens ?? 0;
|
|
22
|
+
outputTokens += step.usage?.outputTokens ?? 0;
|
|
23
|
+
}
|
|
24
|
+
return { inputTokens, outputTokens, totalTokens: inputTokens + outputTokens };
|
|
25
|
+
}
|
|
26
|
+
/** The sum of two usages; a total a provider omitted is input plus output. */
|
|
27
|
+
export function sumUsage(a, b) {
|
|
28
|
+
const total = (u) => u.totalTokens ?? (u.inputTokens ?? 0) + (u.outputTokens ?? 0);
|
|
29
|
+
return {
|
|
30
|
+
inputTokens: (a.inputTokens ?? 0) + (b.inputTokens ?? 0),
|
|
31
|
+
outputTokens: (a.outputTokens ?? 0) + (b.outputTokens ?? 0),
|
|
32
|
+
totalTokens: total(a) + total(b),
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=usage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usage.js","sourceRoot":"","sources":["../src/usage.ts"],"names":[],"mappings":"AAAA;;GAEG;AAQH,2EAA2E;AAC3E,MAAM,UAAU,SAAS,CAAC,KAA6B;IACrD,OAAO;QACL,WAAW,EAAE,KAAK,EAAE,WAAW;QAC/B,YAAY,EAAE,KAAK,EAAE,YAAY;QACjC,WAAW,EAAE,KAAK,EAAE,WAAW;KAChC,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAC1B,KAA4C;IAE5C,IAAI,WAAW,GAAG,CAAC,CAAC;IACpB,IAAI,YAAY,GAAG,CAAC,CAAC;IACrB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,WAAW,IAAI,IAAI,CAAC,KAAK,EAAE,WAAW,IAAI,CAAC,CAAC;QAC5C,YAAY,IAAI,IAAI,CAAC,KAAK,EAAE,YAAY,IAAI,CAAC,CAAC;IAChD,CAAC;IACD,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,WAAW,GAAG,YAAY,EAAE,CAAC;AAChF,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,QAAQ,CAAC,CAAa,EAAE,CAAa;IACnD,MAAM,KAAK,GAAG,CAAC,CAAa,EAAE,EAAE,CAC9B,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,YAAY,IAAI,CAAC,CAAC,CAAC;IAChE,OAAO;QACL,WAAW,EAAE,CAAC,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC;QACxD,YAAY,EAAE,CAAC,CAAC,CAAC,YAAY,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,YAAY,IAAI,CAAC,CAAC;QAC3D,WAAW,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC;KACjC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Conversation windowing: what the model is shown of a long history.
|
|
3
|
+
*
|
|
4
|
+
* Works on `UIMessage`s, the AI SDK's transcript, not stored rows.
|
|
5
|
+
* The default `prepareMessages` applies it; an application that wants
|
|
6
|
+
* to summarise what was pruned does so in its own `prepareMessages`,
|
|
7
|
+
* with its own model, and hands the summary back as `system`.
|
|
8
|
+
*/
|
|
9
|
+
import type { UIMessage } from "ai";
|
|
10
|
+
/** The text parts of a message, joined. Tool and file parts contribute nothing. */
|
|
11
|
+
export declare function extractText(parts: ReadonlyArray<unknown>): string;
|
|
12
|
+
/**
|
|
13
|
+
* A cheap token estimate that does not need a tokenizer.
|
|
14
|
+
*
|
|
15
|
+
* Latin text runs about four characters per token; Cyrillic — and
|
|
16
|
+
* most non-Latin scripts — closer to two, because their byte-pair
|
|
17
|
+
* vocabularies are smaller. A single divisor would under-count a
|
|
18
|
+
* Cyrillic transcript by half and window it far too late.
|
|
19
|
+
*/
|
|
20
|
+
export declare function estimateTokenCount(text: string): number;
|
|
21
|
+
export declare function estimateConversationTokens(messages: ReadonlyArray<UIMessage>): number;
|
|
22
|
+
export type ConversationWindowOptions = {
|
|
23
|
+
/** Keep at most this many non-system messages. */
|
|
24
|
+
maxMessages: number;
|
|
25
|
+
/** Also drop from the front until the estimate fits, when set. */
|
|
26
|
+
maxTokens?: number;
|
|
27
|
+
};
|
|
28
|
+
export type ConversationWindow = {
|
|
29
|
+
windowed: UIMessage[];
|
|
30
|
+
pruned: UIMessage[];
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Keep the most recent messages, always starting the window on a user
|
|
34
|
+
* turn so the model never sees an assistant reply without the message
|
|
35
|
+
* it answered. System messages are never pruned.
|
|
36
|
+
*/
|
|
37
|
+
export declare function applyConversationWindow(messages: ReadonlyArray<UIMessage>, options: ConversationWindowOptions): ConversationWindow;
|
|
38
|
+
//# sourceMappingURL=windowing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"windowing.d.ts","sourceRoot":"","sources":["../src/windowing.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAapC,mFAAmF;AACnF,wBAAgB,WAAW,CAAC,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,GAAG,MAAM,CAKjE;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAUvD;AAED,wBAAgB,0BAA0B,CACxC,QAAQ,EAAE,aAAa,CAAC,SAAS,CAAC,GACjC,MAAM,CAYR;AAED,MAAM,MAAM,yBAAyB,GAAG;IACtC,kDAAkD;IAClD,WAAW,EAAE,MAAM,CAAC;IACpB,kEAAkE;IAClE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,EAAE,SAAS,EAAE,CAAC;IACtB,MAAM,EAAE,SAAS,EAAE,CAAC;CACrB,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,aAAa,CAAC,SAAS,CAAC,EAClC,OAAO,EAAE,yBAAyB,GACjC,kBAAkB,CAuBpB"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Conversation windowing: what the model is shown of a long history.
|
|
3
|
+
*
|
|
4
|
+
* Works on `UIMessage`s, the AI SDK's transcript, not stored rows.
|
|
5
|
+
* The default `prepareMessages` applies it; an application that wants
|
|
6
|
+
* to summarise what was pruned does so in its own `prepareMessages`,
|
|
7
|
+
* with its own model, and hands the summary back as `system`.
|
|
8
|
+
*/
|
|
9
|
+
function isTextPart(part) {
|
|
10
|
+
return (typeof part === "object" &&
|
|
11
|
+
part !== null &&
|
|
12
|
+
part.type === "text" &&
|
|
13
|
+
typeof part.text === "string");
|
|
14
|
+
}
|
|
15
|
+
/** The text parts of a message, joined. Tool and file parts contribute nothing. */
|
|
16
|
+
export function extractText(parts) {
|
|
17
|
+
return parts
|
|
18
|
+
.filter(isTextPart)
|
|
19
|
+
.map((part) => part.text)
|
|
20
|
+
.join(" ");
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* A cheap token estimate that does not need a tokenizer.
|
|
24
|
+
*
|
|
25
|
+
* Latin text runs about four characters per token; Cyrillic — and
|
|
26
|
+
* most non-Latin scripts — closer to two, because their byte-pair
|
|
27
|
+
* vocabularies are smaller. A single divisor would under-count a
|
|
28
|
+
* Cyrillic transcript by half and window it far too late.
|
|
29
|
+
*/
|
|
30
|
+
export function estimateTokenCount(text) {
|
|
31
|
+
// Stryker disable next-line ConditionalExpression: equivalent — the loop below counts nothing in an empty string and returns 0 either way.
|
|
32
|
+
if (!text)
|
|
33
|
+
return 0;
|
|
34
|
+
let nonLatin = 0;
|
|
35
|
+
for (const char of text) {
|
|
36
|
+
const code = char.codePointAt(0) ?? 0;
|
|
37
|
+
if (code > 0x024f)
|
|
38
|
+
nonLatin++;
|
|
39
|
+
}
|
|
40
|
+
const latin = text.length - nonLatin;
|
|
41
|
+
return Math.ceil(latin / 4 + nonLatin / 2);
|
|
42
|
+
}
|
|
43
|
+
export function estimateConversationTokens(messages) {
|
|
44
|
+
let total = 0;
|
|
45
|
+
for (const message of messages) {
|
|
46
|
+
// Tool payloads are not text but still cost tokens; count their
|
|
47
|
+
// serialised size at the Latin rate.
|
|
48
|
+
for (const part of message.parts) {
|
|
49
|
+
total += isTextPart(part)
|
|
50
|
+
? estimateTokenCount(part.text)
|
|
51
|
+
: Math.ceil(JSON.stringify(part).length / 4);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return total;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Keep the most recent messages, always starting the window on a user
|
|
58
|
+
* turn so the model never sees an assistant reply without the message
|
|
59
|
+
* it answered. System messages are never pruned.
|
|
60
|
+
*/
|
|
61
|
+
export function applyConversationWindow(messages, options) {
|
|
62
|
+
const system = messages.filter((message) => message.role === "system");
|
|
63
|
+
const turns = messages.filter((message) => message.role !== "system");
|
|
64
|
+
let start = Math.max(0, turns.length - options.maxMessages);
|
|
65
|
+
// Stryker disable next-line ConditionalExpression: equivalent — with no budget the comparison against undefined is false, so the loop exits on its first test.
|
|
66
|
+
if (options.maxTokens !== undefined) {
|
|
67
|
+
while (start < turns.length - 1 &&
|
|
68
|
+
estimateConversationTokens(turns.slice(start)) > options.maxTokens) {
|
|
69
|
+
start++;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// Open on a user message. If none follows, keep the last turn: a
|
|
73
|
+
// window of nothing is worse than one that opens mid-exchange.
|
|
74
|
+
// Stryker disable next-line OptionalChaining: equivalent — the condition to its left has already proved the index is in range.
|
|
75
|
+
while (start < turns.length - 1 && turns[start]?.role !== "user")
|
|
76
|
+
start++;
|
|
77
|
+
return {
|
|
78
|
+
windowed: [...system, ...turns.slice(start)],
|
|
79
|
+
pruned: turns.slice(0, start),
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=windowing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"windowing.js","sourceRoot":"","sources":["../src/windowing.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@intelligo-dev/chat",
|
|
3
|
+
"version": "1.0.0-beta.13",
|
|
4
|
+
"description": "The AI-SDK-native chat transport: one Route Handler with auth, rate limits, feature gates, credits and persistence.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"intelligo",
|
|
7
|
+
"ai-saas",
|
|
8
|
+
"saas",
|
|
9
|
+
"typescript",
|
|
10
|
+
"ai-sdk",
|
|
11
|
+
"chat",
|
|
12
|
+
"streaming",
|
|
13
|
+
"llm"
|
|
14
|
+
],
|
|
15
|
+
"license": "Apache-2.0",
|
|
16
|
+
"author": "Turtuvshin Byambaa <toroo.byamba@gmail.com>",
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/intelligo-dev/intelligo.git",
|
|
20
|
+
"directory": "packages/chat"
|
|
21
|
+
},
|
|
22
|
+
"homepage": "https://intelligo.dev/docs/packages/chat",
|
|
23
|
+
"bugs": {
|
|
24
|
+
"url": "https://github.com/intelligo-dev/intelligo/issues"
|
|
25
|
+
},
|
|
26
|
+
"type": "module",
|
|
27
|
+
"exports": {
|
|
28
|
+
".": {
|
|
29
|
+
"types": "./dist/index.d.ts",
|
|
30
|
+
"default": "./dist/index.js"
|
|
31
|
+
},
|
|
32
|
+
"./client": {
|
|
33
|
+
"types": "./dist/client.d.ts",
|
|
34
|
+
"default": "./dist/client.js"
|
|
35
|
+
},
|
|
36
|
+
"./testing": {
|
|
37
|
+
"types": "./dist/testing.d.ts",
|
|
38
|
+
"default": "./dist/testing.js"
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"@intelligo-dev/auth": "1.0.0-beta.13",
|
|
43
|
+
"@intelligo-dev/billing": "1.0.0-beta.13",
|
|
44
|
+
"@intelligo-dev/core": "1.0.0-beta.13",
|
|
45
|
+
"@intelligo-dev/executions": "1.0.0-beta.13"
|
|
46
|
+
},
|
|
47
|
+
"peerDependencies": {
|
|
48
|
+
"ai": "^7.0.0"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"@types/node": "^26.6.1",
|
|
52
|
+
"ai": "^7.0.103",
|
|
53
|
+
"typescript": "^5.9.3"
|
|
54
|
+
},
|
|
55
|
+
"files": [
|
|
56
|
+
"dist",
|
|
57
|
+
"src",
|
|
58
|
+
"!src/**/*.test.ts",
|
|
59
|
+
"!src/**/*.test.tsx",
|
|
60
|
+
"!src/**/__tests__/**",
|
|
61
|
+
"LICENSE",
|
|
62
|
+
"NOTICE",
|
|
63
|
+
"README.md",
|
|
64
|
+
"!dist/**/*.tsbuildinfo"
|
|
65
|
+
],
|
|
66
|
+
"publishConfig": {
|
|
67
|
+
"access": "public"
|
|
68
|
+
},
|
|
69
|
+
"engines": {
|
|
70
|
+
"node": ">=22.14"
|
|
71
|
+
},
|
|
72
|
+
"sideEffects": false,
|
|
73
|
+
"scripts": {
|
|
74
|
+
"type-check": "tsc --noEmit",
|
|
75
|
+
"lint": "eslint .",
|
|
76
|
+
"build": "tsc -p tsconfig.build.json && node ../../scripts/fix-esm-extensions.mjs dist"
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stream a document into the chat canvas from inside a tool, as three
|
|
3
|
+
* calls over one `data-chat-artifact` part:
|
|
4
|
+
*
|
|
5
|
+
* const doc = createArtifactWriter(turn, { kind: "text", title });
|
|
6
|
+
* for (const chunk of chunks) doc.append(chunk);
|
|
7
|
+
* const saved = await saveDocument(actor, { id: doc.id, title, content, kind });
|
|
8
|
+
* doc.finish({ documentId: saved.id });
|
|
9
|
+
*
|
|
10
|
+
* Deltas are transient parts under the writer's `id` — the client
|
|
11
|
+
* accumulates them and nothing is persisted mid-stream. The `ready`
|
|
12
|
+
* part is persisted, so the message's card reopens the document from
|
|
13
|
+
* `documentId` after a reload; `error` is persisted too, so a failed
|
|
14
|
+
* document does not reload as a blank card.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import type { ChatArtifactData, ChatDataChunk } from "./parts";
|
|
18
|
+
|
|
19
|
+
export type ArtifactWriterOptions = {
|
|
20
|
+
kind: string;
|
|
21
|
+
title: string;
|
|
22
|
+
/** The part id, and the default document id. A fresh UUID when omitted. */
|
|
23
|
+
id?: string;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export type ArtifactWriter = {
|
|
27
|
+
readonly id: string;
|
|
28
|
+
/** Stream one increment. The first call opens the canvas. */
|
|
29
|
+
append: (delta: string) => void;
|
|
30
|
+
/**
|
|
31
|
+
* Mark the document ready. `content` is persisted in the part only
|
|
32
|
+
* when passed — a document that lives in the documents table is
|
|
33
|
+
* reopened from `documentId` instead.
|
|
34
|
+
*/
|
|
35
|
+
finish: (result?: {
|
|
36
|
+
documentId?: string;
|
|
37
|
+
version?: number;
|
|
38
|
+
content?: string;
|
|
39
|
+
title?: string;
|
|
40
|
+
}) => void;
|
|
41
|
+
fail: (error: unknown) => void;
|
|
42
|
+
/** Everything appended so far. */
|
|
43
|
+
readonly content: string;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export function createArtifactWriter(
|
|
47
|
+
turn: { write: (chunk: ChatDataChunk) => void },
|
|
48
|
+
options: ArtifactWriterOptions
|
|
49
|
+
): ArtifactWriter {
|
|
50
|
+
const id = options.id ?? crypto.randomUUID();
|
|
51
|
+
let title = options.title;
|
|
52
|
+
let content = "";
|
|
53
|
+
let opened = false;
|
|
54
|
+
let closed = false;
|
|
55
|
+
|
|
56
|
+
const emit = (data: ChatArtifactData, transient: boolean) => {
|
|
57
|
+
turn.write({
|
|
58
|
+
type: "data-chat-artifact",
|
|
59
|
+
id,
|
|
60
|
+
data,
|
|
61
|
+
...(transient ? { transient: true } : {}),
|
|
62
|
+
});
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const base = (): ChatArtifactData => ({
|
|
66
|
+
id,
|
|
67
|
+
kind: options.kind,
|
|
68
|
+
title,
|
|
69
|
+
status: "streaming",
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
return {
|
|
73
|
+
id,
|
|
74
|
+
get content() {
|
|
75
|
+
return content;
|
|
76
|
+
},
|
|
77
|
+
append(delta) {
|
|
78
|
+
if (closed) return;
|
|
79
|
+
content += delta;
|
|
80
|
+
if (!opened) {
|
|
81
|
+
opened = true;
|
|
82
|
+
emit(base(), true);
|
|
83
|
+
}
|
|
84
|
+
emit({ ...base(), delta }, true);
|
|
85
|
+
},
|
|
86
|
+
finish(result = {}) {
|
|
87
|
+
if (closed) return;
|
|
88
|
+
closed = true;
|
|
89
|
+
if (result.title) title = result.title;
|
|
90
|
+
emit(
|
|
91
|
+
{
|
|
92
|
+
...base(),
|
|
93
|
+
status: "ready",
|
|
94
|
+
...(result.documentId ? { documentId: result.documentId } : {}),
|
|
95
|
+
...(result.version !== undefined ? { version: result.version } : {}),
|
|
96
|
+
...(result.content !== undefined ? { content: result.content } : {}),
|
|
97
|
+
},
|
|
98
|
+
false
|
|
99
|
+
);
|
|
100
|
+
},
|
|
101
|
+
fail(error) {
|
|
102
|
+
if (closed) return;
|
|
103
|
+
closed = true;
|
|
104
|
+
emit(
|
|
105
|
+
{
|
|
106
|
+
...base(),
|
|
107
|
+
status: "error",
|
|
108
|
+
error: error instanceof Error ? error.message : String(error),
|
|
109
|
+
},
|
|
110
|
+
false
|
|
111
|
+
);
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
}
|