@opencxh/domain 1.134.14 → 1.136.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/entities/ai-account/vendors.d.ts +14 -0
- package/dist/entities/ai-message/types.d.ts +16 -0
- package/dist/index.cjs +7 -7
- package/dist/index.d.ts +1 -0
- package/dist/index.js +491 -456
- package/dist/platform/ai-attachments.d.ts +113 -0
- package/dist/platform/ai-attachments.test.d.ts +1 -0
- package/dist/platform/ai-tools.d.ts +48 -0
- package/package.json +1 -1
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Files the assistant can be handed.
|
|
3
|
+
*
|
|
4
|
+
* The ask pipeline was text-only in name as well as in fact — `AIMessageInput`
|
|
5
|
+
* declared `type: "text"` and nothing ever set anything else. This is the shape
|
|
6
|
+
* that widens it, plus the two things every caller has to agree on: which
|
|
7
|
+
* formats survive, and how big they may be.
|
|
8
|
+
*
|
|
9
|
+
* Deliberately no parsing here. Anthropic, OpenAI and Gemini all accept images
|
|
10
|
+
* and PDFs directly, so the bytes go to the model and there is no document
|
|
11
|
+
* extractor to own. Office formats are the price of that: no vendor takes a
|
|
12
|
+
* `.docx`, so we say so instead of failing quietly.
|
|
13
|
+
*/
|
|
14
|
+
/** What we can do with a file, decided by its mime type. */
|
|
15
|
+
export type AIAttachmentKind =
|
|
16
|
+
/** Sent as image content; the model actually sees it. */
|
|
17
|
+
"image"
|
|
18
|
+
/** Sent as a document; the model reads the pages. */
|
|
19
|
+
| "pdf"
|
|
20
|
+
/** Inlined into the prompt as text. */
|
|
21
|
+
| "text"
|
|
22
|
+
/** Has a route, but not this one — the existing transcription path. */
|
|
23
|
+
| "audio"
|
|
24
|
+
/** No vendor accepts it and we do not extract it. */
|
|
25
|
+
| "unsupported";
|
|
26
|
+
/**
|
|
27
|
+
* Classify a file. Matches on the full mime type rather than a prefix: `image/*`
|
|
28
|
+
* would wave through `image/tiff` and `image/heic`, which no vendor accepts and
|
|
29
|
+
* which are common enough coming off a phone to matter.
|
|
30
|
+
*/
|
|
31
|
+
export declare function aiAttachmentKind(mimeType: string | undefined | null): AIAttachmentKind;
|
|
32
|
+
/**
|
|
33
|
+
* Ceilings, in bytes of the decoded file.
|
|
34
|
+
*
|
|
35
|
+
* Two reasons these are low. Vendors cap individual parts (images around 5MB,
|
|
36
|
+
* PDFs far larger but slow), and base64 adds a third on top of whatever we send.
|
|
37
|
+
* But the binding reason is {@link AI_ATTACHMENT_TURN_BUDGET}: Anthropic and
|
|
38
|
+
* Gemini are stateless, so everything still in the history is re-uploaded on
|
|
39
|
+
* every single turn of the conversation.
|
|
40
|
+
*/
|
|
41
|
+
export declare const AI_ATTACHMENT_LIMITS: Record<Exclude<AIAttachmentKind, "unsupported">, number>;
|
|
42
|
+
/**
|
|
43
|
+
* Total decoded bytes any single turn may carry to the model.
|
|
44
|
+
*
|
|
45
|
+
* This is the number that keeps a long conversation from becoming expensive:
|
|
46
|
+
* attachments from earlier turns are re-hydrated only while they fit under this,
|
|
47
|
+
* oldest dropped first. What falls outside becomes a text placeholder, so the
|
|
48
|
+
* model is told a file was there rather than being left to assume it never was.
|
|
49
|
+
*/
|
|
50
|
+
export declare const AI_ATTACHMENT_TURN_BUDGET: number;
|
|
51
|
+
/** How many attachments one turn may carry, regardless of size. */
|
|
52
|
+
export declare const AI_ATTACHMENT_MAX_PER_TURN = 5;
|
|
53
|
+
/**
|
|
54
|
+
* Where the bytes come from.
|
|
55
|
+
*
|
|
56
|
+
* `inline` exists only on the way in — a file the user just picked. It is never
|
|
57
|
+
* persisted: storing base64 on the message would bloat the row and, worse, make
|
|
58
|
+
* the history re-send it forever. The other two are references the server can
|
|
59
|
+
* re-read on demand, which is why "attach something already in the product"
|
|
60
|
+
* costs nothing to keep.
|
|
61
|
+
*/
|
|
62
|
+
export type AIAttachmentSource =
|
|
63
|
+
/** Base64 of the file, for this request only. */
|
|
64
|
+
{
|
|
65
|
+
kind: "inline";
|
|
66
|
+
data: string;
|
|
67
|
+
}
|
|
68
|
+
/** An attachment on a communication activity (a mail attachment). */
|
|
69
|
+
| {
|
|
70
|
+
kind: "activity";
|
|
71
|
+
activityId: string;
|
|
72
|
+
attachmentId: string;
|
|
73
|
+
}
|
|
74
|
+
/** A file in the storage app. */
|
|
75
|
+
| {
|
|
76
|
+
kind: "storage";
|
|
77
|
+
fileId: string;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* The bytes are gone: an inline file that has been persisted, or one dropped
|
|
81
|
+
* to stay inside the turn budget. Kept rather than removed so the model and
|
|
82
|
+
* the UI can both say "there was a file here".
|
|
83
|
+
*/
|
|
84
|
+
| {
|
|
85
|
+
kind: "expired";
|
|
86
|
+
};
|
|
87
|
+
export interface AIAttachment {
|
|
88
|
+
filename: string;
|
|
89
|
+
mimeType: string;
|
|
90
|
+
/** Decoded size in bytes. Set by the client for `inline`, by the server otherwise. */
|
|
91
|
+
size: number;
|
|
92
|
+
source: AIAttachmentSource;
|
|
93
|
+
}
|
|
94
|
+
/** An attachment the server has resolved to actual bytes, ready for an adapter. */
|
|
95
|
+
export interface ResolvedAIAttachment {
|
|
96
|
+
filename: string;
|
|
97
|
+
mimeType: string;
|
|
98
|
+
kind: Exclude<AIAttachmentKind, "unsupported">;
|
|
99
|
+
/** Base64 of the file — what every vendor's inline-data field wants. */
|
|
100
|
+
data: string;
|
|
101
|
+
size: number;
|
|
102
|
+
}
|
|
103
|
+
/** Why an attachment did not make it to the model. */
|
|
104
|
+
export interface RejectedAIAttachment {
|
|
105
|
+
filename: string;
|
|
106
|
+
reason: "unsupported" | "too-large" | "unreadable" | "over-budget" | "too-many";
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Is this file acceptable at all? Checked on both sides: the client refuses
|
|
110
|
+
* before uploading, the server refuses before spending a model call. Size is in
|
|
111
|
+
* decoded bytes.
|
|
112
|
+
*/
|
|
113
|
+
export declare function aiAttachmentRejection(mimeType: string, size: number): RejectedAIAttachment["reason"] | null;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -44,11 +44,59 @@ export interface AiToolCall {
|
|
|
44
44
|
name: string;
|
|
45
45
|
arguments: Record<string, unknown>;
|
|
46
46
|
}
|
|
47
|
+
/**
|
|
48
|
+
* Something a tool read, so the answer can say where it looked.
|
|
49
|
+
*
|
|
50
|
+
* A tool's `content` is prose written for the model, which means the provenance
|
|
51
|
+
* inside it — an article id, a conversation title — is only recoverable by
|
|
52
|
+
* parsing text the tool is free to reformat. This is the same information handed
|
|
53
|
+
* over as data instead.
|
|
54
|
+
*
|
|
55
|
+
* These are the things that were **consulted**, not a claim about which ones the
|
|
56
|
+
* answer leaned on: a search that returns five articles returns five sources
|
|
57
|
+
* whether the model used one of them or all five. Label them accordingly in the
|
|
58
|
+
* UI; asking the model to cite would be more precise and less trustworthy,
|
|
59
|
+
* because a model will invent a reference.
|
|
60
|
+
*/
|
|
61
|
+
export interface ToolSource {
|
|
62
|
+
/**
|
|
63
|
+
* What sort of thing this is, e.g. `"kb-article"`, `"memory"`, `"interaction"`.
|
|
64
|
+
* Open string: an app may cite something the platform has no notion of, and a
|
|
65
|
+
* closed union would need a domain change per app.
|
|
66
|
+
*/
|
|
67
|
+
kind: string;
|
|
68
|
+
/** Shown to the user. */
|
|
69
|
+
title: string;
|
|
70
|
+
/** Stable id within its kind, when there is one. */
|
|
71
|
+
id?: string;
|
|
72
|
+
/** A second line: a snippet, a date, an author. */
|
|
73
|
+
detail?: string;
|
|
74
|
+
/**
|
|
75
|
+
* Shell-absolute in-product route, including the `/apps/<app>` prefix — the
|
|
76
|
+
* source may well belong to a different app than the one showing it.
|
|
77
|
+
*
|
|
78
|
+
* Follow it with the **kernel** router (`sdk` from `@opencxh/app-sdk`), not an
|
|
79
|
+
* app's own: `createApp().router.navigate` prefixes the calling app's id, which
|
|
80
|
+
* would turn `/apps/kb/…` into `/apps/ai/apps/kb/…`.
|
|
81
|
+
*
|
|
82
|
+
* Absent when the thing has no page of its own — a memory item, for instance —
|
|
83
|
+
* which is a reason to show it without a link, not a reason to hide it.
|
|
84
|
+
*/
|
|
85
|
+
url?: string;
|
|
86
|
+
}
|
|
47
87
|
/** The result of executing a tool call, fed back to the model. */
|
|
48
88
|
export interface AiToolResult {
|
|
49
89
|
id: string;
|
|
50
90
|
content: string;
|
|
51
91
|
isError?: boolean;
|
|
92
|
+
/**
|
|
93
|
+
* What this call read. Optional and additive, like the fields on
|
|
94
|
+
* {@link AiToolDescriptor}: a tool that sets nothing behaves exactly as before.
|
|
95
|
+
*
|
|
96
|
+
* Persisted for free — `ToolTraceEntry.result` already rides along on the
|
|
97
|
+
* stored `AIMessage`, so the thread keeps its provenance without a new entity.
|
|
98
|
+
*/
|
|
99
|
+
sources?: ToolSource[];
|
|
52
100
|
}
|
|
53
101
|
/**
|
|
54
102
|
* Returned by an app's `GET /provider/ai-tools/describe`.
|