@protobase/schema 0.1.6 → 0.3.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/assistant/apply-event.d.ts +6 -0
- package/dist/assistant/apply-event.js +46 -0
- package/dist/assistant/event-stream.d.ts +8 -0
- package/dist/assistant/event-stream.js +31 -0
- package/dist/assistant/protocol.d.ts +104 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.js +3 -1
- package/package.json +1 -1
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { AssistantEvent, AssistantState } from "./protocol.js";
|
|
2
|
+
//#region src/assistant/apply-event.d.ts
|
|
3
|
+
export declare const emptyAssistantState: AssistantState;
|
|
4
|
+
/** The state after one event; a `part` for a message not seen yet starts an assistant message. */
|
|
5
|
+
export declare const applyAssistantEvent: (state: AssistantState, event: AssistantEvent) => AssistantState;
|
|
6
|
+
//#endregion
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
//#region src/assistant/apply-event.ts
|
|
2
|
+
const emptyAssistantState = {
|
|
3
|
+
messages: [],
|
|
4
|
+
replying: false
|
|
5
|
+
};
|
|
6
|
+
const upsert = (items, item) => {
|
|
7
|
+
const index = items.findIndex((entry) => entry.id === item.id);
|
|
8
|
+
return index === -1 ? [...items, item] : items.map((entry, at) => at === index ? item : entry);
|
|
9
|
+
};
|
|
10
|
+
const withPart = (messages, messageId, part) => {
|
|
11
|
+
const message = messages.find((entry) => entry.id === messageId);
|
|
12
|
+
const next = message ? {
|
|
13
|
+
...message,
|
|
14
|
+
parts: upsert(message.parts, part)
|
|
15
|
+
} : {
|
|
16
|
+
id: messageId,
|
|
17
|
+
from: "assistant",
|
|
18
|
+
parts: [part]
|
|
19
|
+
};
|
|
20
|
+
return upsert(messages, next);
|
|
21
|
+
};
|
|
22
|
+
/** The state after one event; a `part` for a message not seen yet starts an assistant message. */
|
|
23
|
+
const applyAssistantEvent = (state, event) => {
|
|
24
|
+
switch (event.type) {
|
|
25
|
+
case "state": return event.state;
|
|
26
|
+
case "message": return {
|
|
27
|
+
...state,
|
|
28
|
+
messages: upsert(state.messages, event.message)
|
|
29
|
+
};
|
|
30
|
+
case "part": return {
|
|
31
|
+
...state,
|
|
32
|
+
messages: withPart(state.messages, event.messageId, event.part)
|
|
33
|
+
};
|
|
34
|
+
case "patch": {
|
|
35
|
+
const { replying = state.replying, status = state.status, placeholder = state.placeholder } = event;
|
|
36
|
+
return {
|
|
37
|
+
messages: state.messages,
|
|
38
|
+
replying,
|
|
39
|
+
...status !== null && status !== void 0 && { status },
|
|
40
|
+
...placeholder !== null && placeholder !== void 0 && { placeholder }
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
//#endregion
|
|
46
|
+
export { applyAssistantEvent, emptyAssistantState };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
//#region src/assistant/event-stream.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Reads a `text/event-stream` body and calls `onData` with the data of every event, its `data:` lines joined by
|
|
4
|
+
* newlines. Comments, event names and ids are skipped: the assistant protocol and chat completions only use data.
|
|
5
|
+
* Aborting `signal` cancels the body and resolves.
|
|
6
|
+
*/
|
|
7
|
+
export declare const readEventStream: (body: ReadableStream<Uint8Array>, onData: (data: string) => void, signal?: AbortSignal) => Promise<void>;
|
|
8
|
+
//#endregion
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
//#region src/assistant/event-stream.ts
|
|
2
|
+
/**
|
|
3
|
+
* Reads a `text/event-stream` body and calls `onData` with the data of every event, its `data:` lines joined by
|
|
4
|
+
* newlines. Comments, event names and ids are skipped: the assistant protocol and chat completions only use data.
|
|
5
|
+
* Aborting `signal` cancels the body and resolves.
|
|
6
|
+
*/
|
|
7
|
+
const readEventStream = async (body, onData, signal) => {
|
|
8
|
+
const decoder = new TextDecoder();
|
|
9
|
+
const reader = body.getReader();
|
|
10
|
+
signal?.addEventListener("abort", () => void reader.cancel(), { once: true });
|
|
11
|
+
let buffer = "";
|
|
12
|
+
let data = [];
|
|
13
|
+
const line = (text) => {
|
|
14
|
+
if (text === "") {
|
|
15
|
+
if (data.length > 0) onData(data.join("\n"));
|
|
16
|
+
data = [];
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
if (text.startsWith("data:")) data.push(text.slice(text.startsWith("data: ") ? 6 : 5));
|
|
20
|
+
};
|
|
21
|
+
for (;;) {
|
|
22
|
+
const { done, value } = await reader.read();
|
|
23
|
+
buffer += done ? decoder.decode() : decoder.decode(value, { stream: true });
|
|
24
|
+
const lines = buffer.split(/\r\n|\r|\n/);
|
|
25
|
+
buffer = done ? "" : lines.pop() ?? "";
|
|
26
|
+
lines.forEach(line);
|
|
27
|
+
if (done) return line("");
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
//#endregion
|
|
31
|
+
export { readEventStream };
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
//#region src/assistant/protocol.d.ts
|
|
2
|
+
export type AssistantTone = 'neutral' | 'info' | 'success' | 'warning' | 'danger';
|
|
3
|
+
/** A button on a card. Clicking it posts `{ partId, actionId }`; with `confirm`, only after the user confirms that text. */
|
|
4
|
+
export type AssistantAction = {
|
|
5
|
+
id: string;
|
|
6
|
+
label: string;
|
|
7
|
+
style?: 'primary' | 'secondary' | 'ghost' | 'danger';
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
/** A line under the buttons, such as why one is disabled. */
|
|
10
|
+
hint?: string;
|
|
11
|
+
confirm?: string;
|
|
12
|
+
};
|
|
13
|
+
export type AssistantStepState = 'pending' | 'running' | 'done' | 'failed';
|
|
14
|
+
export type AssistantStep = {
|
|
15
|
+
label: string;
|
|
16
|
+
state: AssistantStepState;
|
|
17
|
+
};
|
|
18
|
+
/** Changed lines: `+` added, `-` removed, anything else context; `start` is the first line's number. */
|
|
19
|
+
export type AssistantDiff = {
|
|
20
|
+
path?: string;
|
|
21
|
+
source: string;
|
|
22
|
+
start?: number;
|
|
23
|
+
};
|
|
24
|
+
export type AssistantTextPart = {
|
|
25
|
+
type: 'text';
|
|
26
|
+
id: string;
|
|
27
|
+
text: string;
|
|
28
|
+
};
|
|
29
|
+
/** Rows of values; `null` stays visible, objects show as JSON. `truncated` says the rows stop at a limit. */
|
|
30
|
+
export type AssistantTablePart = {
|
|
31
|
+
type: 'table';
|
|
32
|
+
id: string;
|
|
33
|
+
columns: string[];
|
|
34
|
+
rows: unknown[][];
|
|
35
|
+
caption?: string;
|
|
36
|
+
truncated?: boolean;
|
|
37
|
+
};
|
|
38
|
+
export type AssistantCardPart = {
|
|
39
|
+
type: 'card';
|
|
40
|
+
id: string;
|
|
41
|
+
title: string;
|
|
42
|
+
tone?: AssistantTone;
|
|
43
|
+
/** Short text at the end of the title row. */
|
|
44
|
+
badge?: string;
|
|
45
|
+
body?: string;
|
|
46
|
+
/** Monospace text, such as a query. */
|
|
47
|
+
code?: string;
|
|
48
|
+
fields?: Array<{
|
|
49
|
+
label: string;
|
|
50
|
+
value: string;
|
|
51
|
+
}>;
|
|
52
|
+
steps?: AssistantStep[];
|
|
53
|
+
diffs?: AssistantDiff[];
|
|
54
|
+
/** A muted line under the content, such as what happened to the card. */
|
|
55
|
+
note?: string;
|
|
56
|
+
actions?: AssistantAction[];
|
|
57
|
+
};
|
|
58
|
+
export type AssistantPart = AssistantTextPart | AssistantTablePart | AssistantCardPart;
|
|
59
|
+
export type AssistantMessage = {
|
|
60
|
+
id: string;
|
|
61
|
+
from: 'user' | 'assistant';
|
|
62
|
+
parts: AssistantPart[];
|
|
63
|
+
};
|
|
64
|
+
export type AssistantState = {
|
|
65
|
+
messages: AssistantMessage[];
|
|
66
|
+
/** The backend is answering: the user can write but not send. */
|
|
67
|
+
replying: boolean;
|
|
68
|
+
/** A line in the dock's header. */
|
|
69
|
+
status?: string;
|
|
70
|
+
/** The composer's placeholder; a new one focuses the composer. */
|
|
71
|
+
placeholder?: string;
|
|
72
|
+
};
|
|
73
|
+
/**
|
|
74
|
+
* What the event stream sends. `state` replaces everything and always comes first on a connection; `message` adds a
|
|
75
|
+
* message or replaces the one with its id; `part` adds a part to a message or replaces the one with its id; `patch`
|
|
76
|
+
* changes the top-level fields, `null` clearing one.
|
|
77
|
+
*/
|
|
78
|
+
export type AssistantEvent = {
|
|
79
|
+
type: 'state';
|
|
80
|
+
state: AssistantState;
|
|
81
|
+
} | {
|
|
82
|
+
type: 'message';
|
|
83
|
+
message: AssistantMessage;
|
|
84
|
+
} | {
|
|
85
|
+
type: 'part';
|
|
86
|
+
messageId: string;
|
|
87
|
+
part: AssistantPart;
|
|
88
|
+
} | {
|
|
89
|
+
type: 'patch';
|
|
90
|
+
replying?: boolean;
|
|
91
|
+
status?: string | null;
|
|
92
|
+
placeholder?: string | null;
|
|
93
|
+
};
|
|
94
|
+
/** `POST <url>/messages`; `page` is where the user is in the app, below its base path, such as `/orders/42?status=open`. */
|
|
95
|
+
export type AssistantMessageRequest = {
|
|
96
|
+
text: string;
|
|
97
|
+
page?: string;
|
|
98
|
+
};
|
|
99
|
+
/** `POST <url>/actions` */
|
|
100
|
+
export type AssistantActionRequest = {
|
|
101
|
+
partId: string;
|
|
102
|
+
actionId: string;
|
|
103
|
+
};
|
|
104
|
+
//#endregion
|
package/dist/index.d.ts
CHANGED
|
@@ -25,4 +25,7 @@ import { pickView } from "./access/pick-view.js";
|
|
|
25
25
|
import { AccessSource, ResolveOptions, ResolvedAccess, RowFilterOperation, accessWarnings, checkRecord, fieldsUsedBy, resolveAccess } from "./access/resolve.js";
|
|
26
26
|
import { restrictModel } from "./access/restrict.js";
|
|
27
27
|
import "./access/index.js";
|
|
28
|
-
|
|
28
|
+
import { AssistantAction, AssistantActionRequest, AssistantCardPart, AssistantDiff, AssistantEvent, AssistantMessage, AssistantMessageRequest, AssistantPart, AssistantState, AssistantStep, AssistantStepState, AssistantTablePart, AssistantTextPart, AssistantTone } from "./assistant/protocol.js";
|
|
29
|
+
import { applyAssistantEvent, emptyAssistantState } from "./assistant/apply-event.js";
|
|
30
|
+
import { readEventStream } from "./assistant/event-stream.js";
|
|
31
|
+
export { type AccessAction, type AccessContext, type AccessFn, type AccessResult, type AccessSource, type AccessUser, type ActionModel, type ActionRun, type AssistantAction, type AssistantActionRequest, type AssistantCardPart, type AssistantDiff, type AssistantEvent, type AssistantMessage, type AssistantMessageRequest, type AssistantPart, type AssistantState, type AssistantStep, type AssistantStepState, type AssistantTablePart, type AssistantTextPart, type AssistantTone, type Capability, type CapabilityAction, type CapabilityScope, type ChartGranularity, type ChartModel, type ChartRange, type CheckResult, type CheckedFilter, type CompareOp, type DatePreset, type DurationLiteral, type DurationUnit, type EvaluateOptions, type Field, type FieldAccess, type FieldFormat, type FieldModel, type FieldPath, type FieldRule, type FieldType, type FieldViewModel, type FilterError, type FilterErrorCode, type FilterExpr, type FilterLimits, type FilterOf, type FilterParse, type FilterValue, type FilterWidgetModel, type InferRecord, type KeyType, type KeyValue, type LayoutItemModel, type ListModel, type ListQuery, type Literal, type NavModel, type NavRecentModel, type NowValue, type OrderByCheck, type OrderByItem, type OrderByParse, type RecordKey, type RelatedModel, type ResolveOptions, type ResolvedAccess, type ResourceModel, type Roles, type RolesOptions, type RowFilterOperation, type Rule, type SaveFeedback, type SearchMatch, type SearchResultModel, type SearchTerm, type SortSpec, type Span, type StatusTone, type UserMenuItemModel, type UserMenuModel, type UserMenuSource, type ViewModel, accessWarnings, applyAssistantEvent, checkFilter, checkOrderBy, checkRecord, createWhere, decodeKey, defaultRecentLimit, defineRoles, emptyAssistantState, encodeKey, enumLabel, evaluateFilter, f, fieldsUsedBy, keyTypes, layout as l, matchedSearchField, matchesSearch, navRecentErrors, parseFilter, parseOrderBy, pickView, printFilter, printOrderBy, readEventStream, resolveAccess, resource, restrictModel, rule, searchTerms, statusTones, termMatches, userMenu, view, where };
|
package/dist/index.js
CHANGED
|
@@ -18,4 +18,6 @@ import { defineRoles } from "./access/roles.js";
|
|
|
18
18
|
import { pickView } from "./access/pick-view.js";
|
|
19
19
|
import { restrictModel } from "./access/restrict.js";
|
|
20
20
|
import { accessWarnings, checkRecord, fieldsUsedBy, resolveAccess } from "./access/resolve.js";
|
|
21
|
-
|
|
21
|
+
import { applyAssistantEvent, emptyAssistantState } from "./assistant/apply-event.js";
|
|
22
|
+
import { readEventStream } from "./assistant/event-stream.js";
|
|
23
|
+
export { accessWarnings, applyAssistantEvent, checkFilter, checkOrderBy, checkRecord, createWhere, decodeKey, defaultRecentLimit, defineRoles, emptyAssistantState, encodeKey, enumLabel, evaluateFilter, f, fieldsUsedBy, keyTypes, layout as l, matchedSearchField, matchesSearch, navRecentErrors, parseFilter, parseOrderBy, pickView, printFilter, printOrderBy, readEventStream, resolveAccess, resource, restrictModel, rule, searchTerms, statusTones, termMatches, userMenu, view, where };
|