@lotics/app-sdk 0.100.1 → 0.101.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/AGENTS.md +32 -47
- package/dist/agent_stream.d.ts +131 -0
- package/dist/ask_ai.d.ts +27 -0
- package/dist/attachments.d.ts +58 -0
- package/dist/chunk-ARV5FAU5.js +1132 -0
- package/dist/comments.d.ts +89 -0
- package/dist/error_report.d.ts +9 -0
- package/dist/folder_pick.d.ts +8 -0
- package/dist/geolocation.d.ts +42 -0
- package/dist/hooks.d.ts +251 -0
- package/dist/{src/index.d.ts → index.d.ts} +13 -22
- package/dist/index.js +31309 -0
- package/dist/index.js.LEGAL.txt +11 -0
- package/dist/members.d.ts +32 -0
- package/dist/mock.d.ts +37 -0
- package/dist/mount.d.ts +19 -0
- package/dist/new_record.d.ts +37 -0
- package/dist/open_app.d.ts +12 -0
- package/dist/open_external.d.ts +10 -0
- package/dist/overlay.d.ts +25 -0
- package/dist/queries.d.ts +231 -0
- package/dist/recording.d.ts +47 -0
- package/dist/recording_state.d.ts +43 -0
- package/dist/rename_file.d.ts +13 -0
- package/dist/router.d.ts +10 -0
- package/dist/router.js +97 -0
- package/dist/row.d.ts +87 -0
- package/dist/rpc.d.ts +114 -0
- package/dist/select.d.ts +24 -0
- package/dist/shared_types.d.ts +8 -0
- package/dist/store.d.ts +43 -0
- package/dist/types.d.ts +36 -0
- package/dist/upload/optimize.d.ts +30 -0
- package/dist/upload/pipeline.d.ts +36 -0
- package/dist/upload/transport.d.ts +19 -0
- package/dist/url_params.d.ts +55 -0
- package/dist/use_recents.d.ts +15 -0
- package/dist/{src/use_url_state.d.ts → use_url_state.d.ts} +0 -2
- package/dist/viewer.d.ts +41 -0
- package/dist/written.d.ts +77 -0
- package/docs/ai.md +74 -133
- package/docs/data_fetching.md +209 -290
- package/docs/files.md +61 -51
- package/docs/members_and_options.md +92 -62
- package/docs/mutations.md +135 -205
- package/docs/navigation_and_state.md +26 -35
- package/docs/queries.md +144 -207
- package/docs/recipes.md +21 -45
- package/docs/runtime.md +74 -137
- package/docs/security.md +8 -11
- package/docs/workflows.md +189 -174
- package/package.json +27 -28
- package/dist/src/agent_stream.d.ts +0 -200
- package/dist/src/agent_stream.js +0 -314
- package/dist/src/ask_ai.d.ts +0 -40
- package/dist/src/ask_ai.js +0 -35
- package/dist/src/attachments.d.ts +0 -68
- package/dist/src/attachments.js +0 -93
- package/dist/src/comments.d.ts +0 -127
- package/dist/src/comments.js +0 -192
- package/dist/src/download.js +0 -54
- package/dist/src/geolocation.d.ts +0 -64
- package/dist/src/geolocation.js +0 -96
- package/dist/src/hooks.d.ts +0 -781
- package/dist/src/hooks.js +0 -860
- package/dist/src/index.js +0 -34
- package/dist/src/members.d.ts +0 -105
- package/dist/src/members.js +0 -62
- package/dist/src/mock.d.ts +0 -118
- package/dist/src/mock.js +0 -124
- package/dist/src/mount.d.ts +0 -47
- package/dist/src/mount.js +0 -34
- package/dist/src/new_record.d.ts +0 -74
- package/dist/src/new_record.js +0 -117
- package/dist/src/open_app.d.ts +0 -15
- package/dist/src/open_app.js +0 -18
- package/dist/src/open_external.d.ts +0 -16
- package/dist/src/open_external.js +0 -19
- package/dist/src/recording.d.ts +0 -59
- package/dist/src/recording.js +0 -30
- package/dist/src/recording_state.d.ts +0 -59
- package/dist/src/recording_state.js +0 -94
- package/dist/src/router.d.ts +0 -17
- package/dist/src/router.js +0 -144
- package/dist/src/row.d.ts +0 -159
- package/dist/src/row.js +0 -254
- package/dist/src/rpc.d.ts +0 -207
- package/dist/src/rpc.js +0 -904
- package/dist/src/select.d.ts +0 -48
- package/dist/src/select.js +0 -40
- package/dist/src/types.d.ts +0 -115
- package/dist/src/types.js +0 -1
- package/dist/src/upload/optimize.d.ts +0 -54
- package/dist/src/upload/optimize.js +0 -207
- package/dist/src/upload/pipeline.d.ts +0 -55
- package/dist/src/upload/pipeline.js +0 -52
- package/dist/src/upload/transport.d.ts +0 -42
- package/dist/src/upload/transport.js +0 -128
- package/dist/src/url_params.d.ts +0 -93
- package/dist/src/url_params.js +0 -215
- package/dist/src/use_optimistic.d.ts +0 -27
- package/dist/src/use_optimistic.js +0 -27
- package/dist/src/use_recents.d.ts +0 -19
- package/dist/src/use_recents.js +0 -71
- package/dist/src/use_url_state.js +0 -73
- package/dist/src/viewer.d.ts +0 -26
- package/dist/src/viewer.js +0 -47
- /package/dist/{src/download.d.ts → download.d.ts} +0 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
export interface AppCommentFile {
|
|
2
|
+
id: string;
|
|
3
|
+
filename: string;
|
|
4
|
+
mime_type: string;
|
|
5
|
+
url?: string;
|
|
6
|
+
thumbnail_url?: string;
|
|
7
|
+
preview_url?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface AppCommentAuthor {
|
|
10
|
+
/** Null for a removed member — fall back explicitly, as with `readMembers`. */
|
|
11
|
+
name: string | null;
|
|
12
|
+
image?: string | null;
|
|
13
|
+
}
|
|
14
|
+
export interface AppComment {
|
|
15
|
+
id: string;
|
|
16
|
+
record_id: string;
|
|
17
|
+
table_id: string;
|
|
18
|
+
member_id: string;
|
|
19
|
+
/**
|
|
20
|
+
* Resolved server-side on every comment, so a cross-role thread is legible
|
|
21
|
+
* without member access. Absent only on the optimistic row, until the refetch.
|
|
22
|
+
*/
|
|
23
|
+
author?: AppCommentAuthor;
|
|
24
|
+
content: string;
|
|
25
|
+
files: AppCommentFile[] | null;
|
|
26
|
+
workspace_id: string;
|
|
27
|
+
created_at: string;
|
|
28
|
+
updated_at: string;
|
|
29
|
+
}
|
|
30
|
+
export interface CommentsState {
|
|
31
|
+
/** Oldest first. */
|
|
32
|
+
comments: AppComment[];
|
|
33
|
+
loading: boolean;
|
|
34
|
+
error: string | null;
|
|
35
|
+
/** A signed-in member and the `comments` capability; gate the composer on it — mutations reject otherwise. */
|
|
36
|
+
available: boolean;
|
|
37
|
+
/** `file_ids` from `useFileUpload().upload()`; no-op when empty. */
|
|
38
|
+
createComment: (input: {
|
|
39
|
+
content: string;
|
|
40
|
+
file_ids?: string[];
|
|
41
|
+
}) => Promise<void>;
|
|
42
|
+
/** Author-only. `files` replaces the set; omitted, the current files are kept. */
|
|
43
|
+
updateComment: (id: string, input: {
|
|
44
|
+
content: string;
|
|
45
|
+
files?: AppCommentFile[];
|
|
46
|
+
}) => Promise<void>;
|
|
47
|
+
/** Author-only. */
|
|
48
|
+
deleteComment: (id: string) => Promise<void>;
|
|
49
|
+
refetch: () => void;
|
|
50
|
+
}
|
|
51
|
+
export interface UseCommentsArgs {
|
|
52
|
+
record_id: string;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* `record_id` must be a real id — an empty string still fetches. Gate the
|
|
56
|
+
* panel on a row's `__source_record_id`, which a grouped query lacks.
|
|
57
|
+
*
|
|
58
|
+
* ```tsx
|
|
59
|
+
* // In a record screen, where an id definitionally exists:
|
|
60
|
+
* const { comments, available, createComment } = useComments({ record_id: recordId });
|
|
61
|
+
*
|
|
62
|
+
* // From a row, gate the whole panel rather than passing a placeholder:
|
|
63
|
+
* {row.__source_record_id && <CommentsPanel recordId={row.__source_record_id} />}
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
export declare function useComments(args: UseCommentsArgs): CommentsState;
|
|
67
|
+
export interface CommentCountsState {
|
|
68
|
+
/** `{ record_id: count }`. */
|
|
69
|
+
counts: Record<string, number>;
|
|
70
|
+
loading: boolean;
|
|
71
|
+
error: string | null;
|
|
72
|
+
/** As `useComments`. */
|
|
73
|
+
available: boolean;
|
|
74
|
+
refetch: () => void;
|
|
75
|
+
}
|
|
76
|
+
export interface UseCommentCountsArgs {
|
|
77
|
+
/** Read off a row's `__source_table_id`, never a pasted `tbl_` (a copy runs over other tables); `undefined` answers `{}`. */
|
|
78
|
+
table_id: string | undefined;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Per-record comment counts for row badges, one server-side `GROUP BY` with no
|
|
82
|
+
* content. App authority, like {@link useComments}.
|
|
83
|
+
*
|
|
84
|
+
* ```tsx
|
|
85
|
+
* const { counts } = useCommentCounts({ table_id: rows[0]?.__source_table_id });
|
|
86
|
+
* // counts[row.__source_record_id] ?? 0
|
|
87
|
+
* ```
|
|
88
|
+
*/
|
|
89
|
+
export declare function useCommentCounts(args: UseCommentCountsArgs): CommentCountsState;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type AppErrorReport } from "./rpc.js";
|
|
2
|
+
/** Where an error surfaced: `mount()`'s `error` / `unhandledrejection` listeners, or a JSON app's spec refused at load. */
|
|
3
|
+
export type AppErrorKind = AppErrorReport["kind"];
|
|
4
|
+
/**
|
|
5
|
+
* Tells the host an error the app did not handle, so it reaches Lotics's error tracking. Fire-and-forget,
|
|
6
|
+
* the first five per page load, and inert standalone. Every origin is cut from what leaves: the app's own
|
|
7
|
+
* is its bearer slug.
|
|
8
|
+
*/
|
|
9
|
+
export declare function reportAppError(kind: AppErrorKind, error: unknown): void;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface FolderPick {
|
|
2
|
+
/** The folder's record id; `null` where the viewer has picked none, `undefined` while it is read. */
|
|
3
|
+
picked: string | null | undefined;
|
|
4
|
+
/** Keep this folder for the viewer, or (`null`) none. */
|
|
5
|
+
pick: (id: string | null) => void;
|
|
6
|
+
}
|
|
7
|
+
/** The folder the viewer works inside for one folder table, and a way to change it. */
|
|
8
|
+
export declare function useFolderPick(table: string): FolderPick;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Geofenced device location, read directly (the host grants the iframe the
|
|
3
|
+
* `geolocation` Permissions-Policy). Failure is a structured `reason`, so the
|
|
4
|
+
* app words its own guidance.
|
|
5
|
+
*/
|
|
6
|
+
/** Center `[latitude, longitude]`, radius in meters. */
|
|
7
|
+
export interface GeofenceZone {
|
|
8
|
+
coordinates: [number, number];
|
|
9
|
+
radius: number;
|
|
10
|
+
}
|
|
11
|
+
export interface GeoCoords {
|
|
12
|
+
latitude: number;
|
|
13
|
+
longitude: number;
|
|
14
|
+
/** Meters. */
|
|
15
|
+
accuracy: number;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* `denied`: no permission. `unavailable`: no fix (services off, no GPS,
|
|
19
|
+
* timeout). `outside`: a fix, in no zone.
|
|
20
|
+
*/
|
|
21
|
+
export type GeofenceOutcome = {
|
|
22
|
+
ok: true;
|
|
23
|
+
coords: GeoCoords;
|
|
24
|
+
} | {
|
|
25
|
+
ok: false;
|
|
26
|
+
reason: "denied" | "unavailable" | "outside";
|
|
27
|
+
};
|
|
28
|
+
export interface GeofenceOptions {
|
|
29
|
+
/** Default 15000. */
|
|
30
|
+
timeoutMs?: number;
|
|
31
|
+
}
|
|
32
|
+
export declare function isWithinZone(latitude: number, longitude: number, zone: GeofenceZone): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* The position checked against the zones; empty `zones` is a plain read.
|
|
35
|
+
*
|
|
36
|
+
* ```tsx
|
|
37
|
+
* const r = await requestGeofencedLocation(DEPOTS);
|
|
38
|
+
* if (!r.ok) return showGeofenceError(r.reason);
|
|
39
|
+
* await chamCong();
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export declare function requestGeofencedLocation(zones: GeofenceZone[], opts?: GeofenceOptions): Promise<GeofenceOutcome>;
|
package/dist/hooks.d.ts
ADDED
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import { type ImageFidelity } from "./upload/optimize.js";
|
|
2
|
+
import { type AttachmentPiles, type AttachmentPilesOptions, type AttachmentsOptions, type AttachmentsState } from "./attachments.js";
|
|
3
|
+
import { type AiContextValue } from "./rpc.js";
|
|
4
|
+
import { type AgentUIPart, type PendingChoice, type AgentRunLanding } from "./agent_stream.js";
|
|
5
|
+
import type { AppWorkflows, AppWorkflowResults, AppAgents, AppAgentResults } from "./types.js";
|
|
6
|
+
import type { ResolvedMember } from "./members.js";
|
|
7
|
+
export type { AgentRunState, AgentUIPart, PendingChoice, ChoiceQuestion, ChoiceOption, AskUserChoiceOutput, AgentRunLanding } from "./agent_stream.js";
|
|
8
|
+
export { buildChoiceOutput } from "./agent_stream.js";
|
|
9
|
+
/**
|
|
10
|
+
* Trigger a workflow by alias. Codegen types the inputs per the declaration;
|
|
11
|
+
* an undeclared alias is a compile error.
|
|
12
|
+
*
|
|
13
|
+
* ```tsx
|
|
14
|
+
* const issue = useWorkflow("issueInvoiceStorageDrop");
|
|
15
|
+
* // Guard the addressing column: a grouped query's rows carry none, and the
|
|
16
|
+
* // workflow would be handed `undefined` where it declares a record.
|
|
17
|
+
* if (row.__source_record_id) await issue({ record_id: row.__source_record_id });
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export declare function useWorkflow<K extends keyof AppWorkflows & string>(alias: K): UseWorkflowFn<K>;
|
|
21
|
+
export declare function useWorkflow(alias: string): (inputs?: Record<string, unknown>) => Promise<WorkflowResult>;
|
|
22
|
+
/**
|
|
23
|
+
* A runner per workflow alias, for a surface whose workflows are data (a spec's acts and saves) rather
|
|
24
|
+
* than a fixed call per component. Each runs exactly as `useWorkflow`'s does.
|
|
25
|
+
*/
|
|
26
|
+
export declare function useWorkflows(aliases: readonly string[]): Readonly<Record<string, (inputs?: Record<string, unknown>) => Promise<WorkflowResult>>>;
|
|
27
|
+
/**
|
|
28
|
+
* Once every record write of this app already sent has answered — a workflow's or an agent's — for a press
|
|
29
|
+
* that reads stored state (an act, a document) after a value typed just before it, so the read never
|
|
30
|
+
* overtakes the write. A write sent after the call is not waited for.
|
|
31
|
+
*/
|
|
32
|
+
export declare function writesSettled(): Promise<void>;
|
|
33
|
+
type ResultDataOf<K extends string> = K extends keyof AppWorkflowResults ? AppWorkflowResults[K] : unknown;
|
|
34
|
+
type UseWorkflowFn<K extends keyof AppWorkflows & string> = AppWorkflows[K] extends Record<string, unknown> ? AppWorkflows[K] extends Record<string, never> ? (inputs?: Record<string, never>) => Promise<WorkflowResult<ResultDataOf<K>>> : (inputs: AppWorkflows[K]) => Promise<WorkflowResult<ResultDataOf<K>>> : (inputs?: Record<string, unknown>) => Promise<WorkflowResult<ResultDataOf<K>>>;
|
|
35
|
+
/**
|
|
36
|
+
* An app-workflow run's result. It never rejects: a gateway failure (524, any
|
|
37
|
+
* 5xx, a non-JSON page) resolves `{ status: "error", message }`. `files` holds
|
|
38
|
+
* any generated document; `data` is the `return({ data })` value.
|
|
39
|
+
*/
|
|
40
|
+
export interface WorkflowResult<TData = unknown> {
|
|
41
|
+
status: "success" | "error";
|
|
42
|
+
message?: string;
|
|
43
|
+
files?: UploadedFile[];
|
|
44
|
+
data?: TData;
|
|
45
|
+
/**
|
|
46
|
+
* Per-input refusals keyed by the declared INPUT name, from the server's
|
|
47
|
+
* payload check or the workflow's `return({ field_errors })`; a table's own
|
|
48
|
+
* refusal keys by `fld_…`. Absent when nothing named a field.
|
|
49
|
+
*/
|
|
50
|
+
field_errors?: Record<string, string>;
|
|
51
|
+
}
|
|
52
|
+
/** A file the host has stored and resolved serving URLs for. */
|
|
53
|
+
export interface UploadedFile {
|
|
54
|
+
id: string;
|
|
55
|
+
filename: string;
|
|
56
|
+
mime_type: string;
|
|
57
|
+
url?: string;
|
|
58
|
+
thumbnail_url?: string;
|
|
59
|
+
}
|
|
60
|
+
interface FileUploadState {
|
|
61
|
+
/**
|
|
62
|
+
* Resolves to the stored file (pass its `id` to a workflow to attach it);
|
|
63
|
+
* rejects on failure. `fidelity` affects photographs only and defaults to
|
|
64
|
+
* `"high"`, which keeps a photographed document legible; `"standard"` suits
|
|
65
|
+
* bulk capture, `"original"` keeps the pixels as evidence.
|
|
66
|
+
*/
|
|
67
|
+
upload: (file: File, options?: {
|
|
68
|
+
fidelity?: ImageFidelity;
|
|
69
|
+
}) => Promise<UploadedFile>;
|
|
70
|
+
uploading: boolean;
|
|
71
|
+
/** Cleared when a new upload starts. */
|
|
72
|
+
error: string | null;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Upload files through a host-mediated presigned upload; works in public and
|
|
76
|
+
* member apps alike.
|
|
77
|
+
*
|
|
78
|
+
* ```tsx
|
|
79
|
+
* const { upload, uploading } = useFileUpload();
|
|
80
|
+
* const submit = useWorkflow("submitApplication");
|
|
81
|
+
* const cccd = await upload(file);
|
|
82
|
+
* await submit({ ...fields, cccd_file_id: cccd.id });
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
85
|
+
export declare function useFileUpload(): FileUploadState;
|
|
86
|
+
/**
|
|
87
|
+
* An add-queue with instant local previews and background uploads. A composer
|
|
88
|
+
* clears when it sends; a record passes its stored files as `landed` and each
|
|
89
|
+
* entry leaves as the pile takes it over.
|
|
90
|
+
*
|
|
91
|
+
* ```tsx
|
|
92
|
+
* const { files, add, remove, clear, uploading, fileIds } = useAttachments();
|
|
93
|
+
* const design = useWorkflow("design");
|
|
94
|
+
* // attach: <Button icon="paperclip" onPress={() => pickFiles({ accept: "image/*" }).then(add)} />
|
|
95
|
+
* // preview: map each AttachedFile to a @lotics/ui DisplayFile (snake_case → camelCase) — the
|
|
96
|
+
* // app owns this data→UI adapter; the SDK never imports @lotics/ui:
|
|
97
|
+
* // files.map((f) => (
|
|
98
|
+
* // <FileThumbnail
|
|
99
|
+
* // file={{ id: f.id, filename: f.filename, mimeType: f.mime_type, url: f.preview_url }}
|
|
100
|
+
* // uploading={f.status === "uploading"} onRemove={() => remove(f.id)} />
|
|
101
|
+
* // ))
|
|
102
|
+
* // send: design({ photo: fileIds[0] }); clear();
|
|
103
|
+
* ```
|
|
104
|
+
*/
|
|
105
|
+
export declare function useAttachments(options?: AttachmentsOptions): AttachmentsState;
|
|
106
|
+
/**
|
|
107
|
+
* {@link useAttachments} for a list of piles in one hook: a hook called once
|
|
108
|
+
* per pile shifts every later hook when the list changes.
|
|
109
|
+
*
|
|
110
|
+
* ```tsx
|
|
111
|
+
* const piles = useAttachmentPiles({ landed: { photos: held.photos, receipts: held.receipts } });
|
|
112
|
+
* const photos = piles.of("photos"); // an AttachmentsState
|
|
113
|
+
* ```
|
|
114
|
+
*/
|
|
115
|
+
export declare function useAttachmentPiles(options?: AttachmentPilesOptions): AttachmentPiles;
|
|
116
|
+
/**
|
|
117
|
+
* Push the current screen's view state to the member's ambient chat agent.
|
|
118
|
+
* Mounting or changing `context` posts it; unmount, a new `slot` or `null`
|
|
119
|
+
* clears it; the newest value per slot wins. Push-only: `records` are raw refs
|
|
120
|
+
* the agent acts on only under the member's own IAM, and `description`/`data`
|
|
121
|
+
* reach its prompt as data.
|
|
122
|
+
*
|
|
123
|
+
* Host caps truncate or drop, never error: `slot` ≤ 50 chars; `description` ≤
|
|
124
|
+
* 1000 chars; `records` ≤ 20; `data` ≤ 2000 JSON chars or dropped; ≤ 8 slots
|
|
125
|
+
* per app, the least recently updated evicted.
|
|
126
|
+
*
|
|
127
|
+
* ```tsx
|
|
128
|
+
* useAiContext("orders_list", {
|
|
129
|
+
* description: `Viewing ${rows.length} orders filtered to status=open, sorted by due date.`,
|
|
130
|
+
* // A grouped query's rows carry no addressing columns.
|
|
131
|
+
* records: rows.flatMap((r) =>
|
|
132
|
+
* r.__source_table_id && r.__source_record_id
|
|
133
|
+
* ? [{ table_id: r.__source_table_id, record_id: r.__source_record_id }]
|
|
134
|
+
* : [],
|
|
135
|
+
* ),
|
|
136
|
+
* data: { filter: "status=open", sort: "due_date desc" },
|
|
137
|
+
* });
|
|
138
|
+
* ```
|
|
139
|
+
*
|
|
140
|
+
* No-ops with no embedding host and in mock mode.
|
|
141
|
+
*/
|
|
142
|
+
export declare function useAiContext(slot: string, context: AiContextValue | null): void;
|
|
143
|
+
interface MembersState {
|
|
144
|
+
members: ResolvedMember[];
|
|
145
|
+
loading: boolean;
|
|
146
|
+
error: string | null;
|
|
147
|
+
}
|
|
148
|
+
export interface MembersOptions {
|
|
149
|
+
/**
|
|
150
|
+
* One member group, by the `grp_…` id a `member` workflow input's `group`
|
|
151
|
+
* declares. Omit for the whole roster.
|
|
152
|
+
*/
|
|
153
|
+
group?: string;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* The organization's members, for an assign picker. Member-only, and gated on
|
|
157
|
+
* the app declaring a `member`-typed workflow input. `name` may be empty —
|
|
158
|
+
* fall back to `email`.
|
|
159
|
+
*
|
|
160
|
+
* ```tsx
|
|
161
|
+
* const { members } = useMembers({ group: GRP.sale });
|
|
162
|
+
* // <Select variant="native" options={members.map((m) => ({
|
|
163
|
+
* // value: m.id, label: m.name || m.email || m.id, image: m.image,
|
|
164
|
+
* // }))} />
|
|
165
|
+
* ```
|
|
166
|
+
*/
|
|
167
|
+
export declare function useMembers(opts?: MembersOptions): MembersState;
|
|
168
|
+
type AgentOutputOf<K extends string> = K extends keyof AppAgentResults ? AppAgentResults[K] : unknown;
|
|
169
|
+
export interface AgentRunOptions {
|
|
170
|
+
/** Groups this run with the session's prior runs as context; a new id clears it. */
|
|
171
|
+
sessionId: string;
|
|
172
|
+
/** Abort the run in flight and start this one. Without it `run()` is
|
|
173
|
+
* single-flight, so a double-press never bills a second run. The replaced
|
|
174
|
+
* run still executes and bills server-side. */
|
|
175
|
+
replace?: boolean;
|
|
176
|
+
}
|
|
177
|
+
export interface UseAgentRun<TInput, TOutput> {
|
|
178
|
+
/** Resolves with how the leg ended — read its `kind`, since the hook's state
|
|
179
|
+
* has not committed yet when it resolves. Single-flight (see `replace`). */
|
|
180
|
+
run: (input: TInput, opts: AgentRunOptions) => Promise<AgentRunLanding<TOutput>>;
|
|
181
|
+
/** Stop listening locally; the run finishes server-side into the session history. */
|
|
182
|
+
abort: () => void;
|
|
183
|
+
/** Stop the run server-side too — what a "Stop" button calls. */
|
|
184
|
+
cancel: () => void;
|
|
185
|
+
/** `awaiting_input`: parked on the agent's question (`pendingChoice`). */
|
|
186
|
+
status: "idle" | "streaming" | "awaiting_input" | "completed" | "error";
|
|
187
|
+
/** The ordered transcript, for `@lotics/ui` `AgentRun` as is. */
|
|
188
|
+
parts: AgentUIPart[];
|
|
189
|
+
/** Non-null exactly while `awaiting_input`; `questions` map onto `ClarifyWizard`. */
|
|
190
|
+
pendingChoice: PendingChoice | null;
|
|
191
|
+
/** Answer the pending ask (one `{value, custom}` per question, by index) and
|
|
192
|
+
* continue the run; resolves like `run`. Rejects when nothing is pending or
|
|
193
|
+
* the server refuses the answer — the run then stays parked. */
|
|
194
|
+
answerChoice: (answers: {
|
|
195
|
+
value: string;
|
|
196
|
+
custom: boolean;
|
|
197
|
+
}[]) => Promise<AgentRunLanding<TOutput>>;
|
|
198
|
+
/** Every `text` part concatenated, live — a free-text agent's result. */
|
|
199
|
+
text: string;
|
|
200
|
+
/** A structured agent's `submit_result` output; `undefined` when none was
|
|
201
|
+
* submitted. The model authored it, so validate inner fields. */
|
|
202
|
+
output?: TOutput;
|
|
203
|
+
error?: string;
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Run a streaming agent by alias. A structured agent's result lands in
|
|
207
|
+
* `output`, a free-text agent's in `text`; `useAgentRuns` reads the session.
|
|
208
|
+
*
|
|
209
|
+
* ```tsx
|
|
210
|
+
* const recognize = useAgentRun("recognize");
|
|
211
|
+
* await recognize.run({ image_file_id }, { sessionId });
|
|
212
|
+
* // <AgentRun parts={recognize.parts} state={recognize.status === "streaming" ? "streaming" : "done"} />
|
|
213
|
+
* // then read recognize.output (structured) or recognize.text (free-text)
|
|
214
|
+
* ```
|
|
215
|
+
*/
|
|
216
|
+
export declare function useAgentRun<K extends keyof AppAgents & string>(alias: K): UseAgentRun<AppAgents[K], AgentOutputOf<K>>;
|
|
217
|
+
export declare function useAgentRun(alias: string): UseAgentRun<Record<string, unknown>, unknown>;
|
|
218
|
+
export interface AgentRunRecord {
|
|
219
|
+
id: string;
|
|
220
|
+
agent_alias: string;
|
|
221
|
+
session_id: string;
|
|
222
|
+
status: string;
|
|
223
|
+
input: Record<string, unknown> | null;
|
|
224
|
+
output: unknown;
|
|
225
|
+
error_message: string | null;
|
|
226
|
+
started_at: string;
|
|
227
|
+
completed_at: string | null;
|
|
228
|
+
/** Single-run GET while `awaiting_input`: rebuilds the ask without the stream. */
|
|
229
|
+
pending_interactive?: {
|
|
230
|
+
tool_call_id: string;
|
|
231
|
+
tool_name: string;
|
|
232
|
+
input: unknown;
|
|
233
|
+
} | null;
|
|
234
|
+
}
|
|
235
|
+
interface AgentRunsState {
|
|
236
|
+
runs: AgentRunRecord[];
|
|
237
|
+
loading: boolean;
|
|
238
|
+
error: string | null;
|
|
239
|
+
refetch: () => void;
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* A session's runs, oldest first. Refetch after a `run(...)` completes.
|
|
243
|
+
*
|
|
244
|
+
* ```tsx
|
|
245
|
+
* const { runs } = useAgentRuns(sessionId);
|
|
246
|
+
* ```
|
|
247
|
+
*/
|
|
248
|
+
export declare function useAgentRuns(sessionId: string, opts?: {
|
|
249
|
+
enabled?: boolean;
|
|
250
|
+
revalidateOnFocus?: boolean;
|
|
251
|
+
}): AgentRunsState;
|
|
@@ -1,26 +1,16 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Lotics App SDK — the runtime + typed hooks bundled into every custom-code
|
|
3
|
-
* app at build time. Apps `import { mount, useQuery, useWorkflow } from
|
|
4
|
-
* "@lotics/app-sdk"` and ship the resulting bundle via `lotics app deploy`.
|
|
5
|
-
*
|
|
6
|
-
* This SDK is data + RPC only — it deliberately does NOT re-export any
|
|
7
|
-
* `@lotics/ui` component, so an app's dependency on the kit is its own and one
|
|
8
|
-
* version answers for it. That is a packaging choice, NOT a limitation: apps
|
|
9
|
-
* import `@lotics/ui` directly as an ordinary dependency. The starter scaffold
|
|
10
|
-
* (`packages/sdk/src/starter_template.ts`) wires it — the kit as a dependency,
|
|
11
|
-
* `@lotics/ui/styles.css` + `fonts.css` in the entry, and `loticsResolve()` as
|
|
12
|
-
* the whole `resolve` block. Build screens by composing kit components (Card,
|
|
13
|
-
* Metric, charts, Table, …), not raw HTML/CSS. See `docs/apps.md` → "Styling
|
|
14
|
-
* & components".
|
|
15
|
-
*/
|
|
1
|
+
/** `@lotics/app-sdk`: hooks, cell readers and `mount()`. Data and RPC only — no kit component. */
|
|
16
2
|
export { mount } from "./mount.js";
|
|
17
3
|
export type { MountOptions } from "./mount.js";
|
|
18
|
-
export {
|
|
19
|
-
export type {
|
|
20
|
-
export
|
|
4
|
+
export { reportAppError } from "./error_report.js";
|
|
5
|
+
export type { AppErrorKind } from "./error_report.js";
|
|
6
|
+
export { useWorkflow, useWorkflows, writesSettled, useFileUpload, useAttachments, useAttachmentPiles, useMembers, useAgentRun, useAgentRuns, useAiContext, buildChoiceOutput, } from "./hooks.js";
|
|
7
|
+
export type { UploadedFile, WorkflowResult, MembersOptions, AgentRunOptions, UseAgentRun, AgentRunLanding, AgentRunRecord, AgentRunState, AgentUIPart, PendingChoice, ChoiceQuestion, ChoiceOption, AskUserChoiceOutput, } from "./hooks.js";
|
|
8
|
+
export { useQuery, useQueries, queryAll, useFieldOptions } from "./queries.js";
|
|
9
|
+
export type { QueryRow, QueryCall, QueryState, RowOf, QueryOptions, ColumnKeyOf, QuerySortKey, QueryFilter, QueryFilterCondition, QueryFilterFieldCondition, QueryFilterRecordIdCondition, QueryFilterGroup, FieldOptions, FieldOptionsState, FieldOptionsOptions, FigureUnits, } from "./queries.js";
|
|
10
|
+
export type { AttachedFile, AttachmentPiles, AttachmentPilesOptions, AttachmentsOptions, AttachmentsState } from "./attachments.js";
|
|
21
11
|
export { useComments, useCommentCounts } from "./comments.js";
|
|
22
12
|
export type { AppComment, AppCommentAuthor, AppCommentFile, CommentsState, UseCommentsArgs, CommentCountsState, UseCommentCountsArgs, } from "./comments.js";
|
|
23
|
-
export { useViewer } from "./viewer.js";
|
|
13
|
+
export { useAppContext, useViewer, useWorkspaceCurrency, useWorkspaceTimezone } from "./viewer.js";
|
|
24
14
|
export { useRecording } from "./recording.js";
|
|
25
15
|
export type { UseRecording } from "./recording.js";
|
|
26
16
|
export type { RecordingState, RecordingInputs } from "./recording_state.js";
|
|
@@ -32,21 +22,22 @@ export { openExternal } from "./open_external.js";
|
|
|
32
22
|
export { openApp } from "./open_app.js";
|
|
33
23
|
export { askAi, type AskAiArgs } from "./ask_ai.js";
|
|
34
24
|
export { downloadFile } from "./download.js";
|
|
25
|
+
export { renameFile } from "./rename_file.js";
|
|
35
26
|
export { readMembers } from "./members.js";
|
|
36
27
|
export type { ResolvedMember } from "./members.js";
|
|
37
28
|
export { readSelect } from "./select.js";
|
|
38
29
|
export type { ResolvedOption } from "./select.js";
|
|
39
30
|
export type { AppFixture, MockQuery, MockQueryCall, MockWorkflow } from "./mock.js";
|
|
40
31
|
export type { AppWorkflows, AppWorkflowResults, AppQueries, AppQueryColumns, AppAgents, AppAgentResults } from "./types.js";
|
|
41
|
-
export { row, readLinks, readFiles, readLocked, readCreatedAt, readUpdatedAt } from "./row.js";
|
|
32
|
+
export { row, readLinks, readFiles, readLocked, readCreatedAt, readUpdatedAt, PENDING } from "./row.js";
|
|
42
33
|
export type { ResolvedLink, AppFile } from "./row.js";
|
|
43
|
-
export { useOptimistic } from "./use_optimistic.js";
|
|
44
|
-
export type { OptimisticApi } from "./use_optimistic.js";
|
|
45
34
|
export { useNewRecord, newRecordId } from "./new_record.js";
|
|
46
35
|
export type { NewRecordApi } from "./new_record.js";
|
|
47
36
|
export { useRecents } from "./use_recents.js";
|
|
48
37
|
export type { RecentsApi, RecentsOptions } from "./use_recents.js";
|
|
49
38
|
export { useUrlState } from "./use_url_state.js";
|
|
39
|
+
export { useFolderPick } from "./folder_pick.js";
|
|
40
|
+
export type { FolderPick } from "./folder_pick.js";
|
|
50
41
|
export type { UrlStateShape, UrlStateValues } from "./use_url_state.js";
|
|
51
42
|
export { urlParam } from "./url_params.js";
|
|
52
43
|
export type { UrlParamCodec, OptionalUrlParamCodec, UrlParams, UrlParamValue, } from "./url_params.js";
|