lemma-sdk 0.2.45 → 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/README.md +16 -0
- package/dist/assistant-events.js +12 -2
- package/dist/browser/lemma-client.js +13683 -4460
- package/dist/browser.d.ts +14 -6
- package/dist/browser.js +35 -6
- package/dist/client.d.ts +4 -0
- package/dist/client.js +16 -4
- package/dist/config.d.ts +4 -0
- package/dist/config.js +7 -1
- package/dist/generated.d.ts +14 -1
- package/dist/generated.js +62 -11
- package/dist/http.d.ts +47 -1
- package/dist/http.js +145 -26
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/namespaces/agents.d.ts +20 -1
- package/dist/namespaces/agents.js +29 -1
- package/dist/namespaces/conversations.d.ts +5 -2
- package/dist/namespaces/conversations.js +2 -0
- package/dist/namespaces/desks.d.ts +9 -0
- package/dist/namespaces/desks.js +6 -0
- package/dist/namespaces/files.d.ts +18 -0
- package/dist/namespaces/files.js +21 -0
- package/dist/namespaces/functions.d.ts +3 -0
- package/dist/namespaces/functions.js +5 -0
- package/dist/namespaces/integrations.d.ts +2 -4
- package/dist/namespaces/integrations.js +2 -2
- package/dist/namespaces/records.d.ts +3 -9
- package/dist/namespaces/records.js +4 -33
- package/dist/namespaces/widgets.d.ts +17 -0
- package/dist/namespaces/widgets.js +16 -0
- package/dist/openapi_client/core/OpenAPI.js +1 -1
- package/dist/openapi_client/index.d.ts +7 -5
- package/dist/openapi_client/index.js +3 -0
- package/dist/openapi_client/models/AgentRunStatus.d.ts +10 -0
- package/dist/openapi_client/models/AgentRunStatus.js +15 -0
- package/dist/openapi_client/models/AgentToolset.d.ts +3 -2
- package/dist/openapi_client/models/AgentToolset.js +2 -1
- package/dist/openapi_client/models/AppTriggerResponseSchema.d.ts +2 -0
- package/dist/openapi_client/models/ApprovalDecisionResponse.d.ts +6 -0
- package/dist/openapi_client/models/AuthProvider.d.ts +4 -0
- package/dist/openapi_client/models/AuthProvider.js +9 -0
- package/dist/openapi_client/models/ConversationResponse.d.ts +4 -0
- package/dist/openapi_client/models/ConversationType.d.ts +2 -1
- package/dist/openapi_client/models/ConversationType.js +1 -0
- package/dist/openapi_client/models/DatastoreQueryRequest.d.ts +1 -1
- package/dist/openapi_client/models/FileSearchResultSchema.d.ts +2 -0
- package/dist/openapi_client/models/FileSignedUrlRequest.d.ts +4 -0
- package/dist/openapi_client/models/FileSignedUrlResponse.d.ts +6 -0
- package/dist/openapi_client/models/FileUrlResponse.d.ts +6 -0
- package/dist/openapi_client/models/FlowRunStatus.d.ts +3 -2
- package/dist/openapi_client/models/FlowRunStatus.js +3 -2
- package/dist/openapi_client/models/MessageKind.d.ts +14 -0
- package/dist/openapi_client/models/MessageKind.js +19 -0
- package/dist/openapi_client/models/MessageResponse.d.ts +5 -6
- package/dist/openapi_client/models/WorkflowRunResponse.d.ts +2 -2
- package/dist/openapi_client/services/AgentConversationsService.d.ts +8 -7
- package/dist/openapi_client/services/AgentConversationsService.js +7 -5
- package/dist/openapi_client/services/ApplicationsService.d.ts +19 -19
- package/dist/openapi_client/services/ApplicationsService.js +48 -44
- package/dist/openapi_client/services/FilesService.d.ts +20 -0
- package/dist/openapi_client/services/FilesService.js +47 -0
- package/dist/openapi_client/services/QueryService.d.ts +1 -1
- package/dist/openapi_client/services/QueryService.js +1 -1
- package/dist/openapi_client/services/RecordsService.d.ts +1 -3
- package/dist/openapi_client/services/RecordsService.js +1 -5
- package/dist/react/assistant-output.d.ts +6 -0
- package/dist/react/assistant-output.js +16 -0
- package/dist/react/useAssistantController.d.ts +8 -1
- package/dist/react/useAssistantController.js +87 -250
- package/dist/react/useAssistantRuntime.js +6 -17
- package/dist/react/useAssistantSession.d.ts +4 -2
- package/dist/react/useAssistantSession.js +6 -7
- package/dist/react/useConversationMessages.d.ts +2 -2
- package/dist/react/useConversationMessages.js +3 -5
- package/dist/react/useRecords.d.ts +1 -1
- package/dist/react/useRecords.js +2 -13
- package/dist/react/useReferencingRecords.d.ts +4 -6
- package/dist/react/useReferencingRecords.js +5 -5
- package/dist/react/useReverseRelatedRecords.d.ts +3 -4
- package/dist/react/useReverseRelatedRecords.js +5 -5
- package/dist/run-utils.d.ts +24 -0
- package/dist/run-utils.js +54 -0
- package/dist/types.d.ts +12 -6
- package/dist/version.d.ts +5 -0
- package/dist/version.js +7 -0
- package/package.json +10 -5
- package/dist/hey_client/client/client.gen.d.ts +0 -2
- package/dist/hey_client/client/client.gen.js +0 -216
- package/dist/hey_client/client/index.d.ts +0 -10
- package/dist/hey_client/client/index.js +0 -6
- package/dist/hey_client/client/types.gen.d.ts +0 -120
- package/dist/hey_client/client/types.gen.js +0 -2
- package/dist/hey_client/client/utils.gen.d.ts +0 -37
- package/dist/hey_client/client/utils.gen.js +0 -228
- package/dist/hey_client/client.gen.d.ts +0 -12
- package/dist/hey_client/client.gen.js +0 -3
- package/dist/hey_client/core/auth.gen.d.ts +0 -25
- package/dist/hey_client/core/auth.gen.js +0 -14
- package/dist/hey_client/core/bodySerializer.gen.d.ts +0 -25
- package/dist/hey_client/core/bodySerializer.gen.js +0 -57
- package/dist/hey_client/core/params.gen.d.ts +0 -43
- package/dist/hey_client/core/params.gen.js +0 -100
- package/dist/hey_client/core/pathSerializer.gen.d.ts +0 -33
- package/dist/hey_client/core/pathSerializer.gen.js +0 -106
- package/dist/hey_client/core/queryKeySerializer.gen.d.ts +0 -18
- package/dist/hey_client/core/queryKeySerializer.gen.js +0 -92
- package/dist/hey_client/core/serverSentEvents.gen.d.ts +0 -71
- package/dist/hey_client/core/serverSentEvents.gen.js +0 -132
- package/dist/hey_client/core/types.gen.d.ts +0 -83
- package/dist/hey_client/core/types.gen.js +0 -2
- package/dist/hey_client/core/utils.gen.d.ts +0 -19
- package/dist/hey_client/core/utils.gen.js +0 -87
- package/dist/hey_client/index.d.ts +0 -2
- package/dist/hey_client/index.js +0 -2
- package/dist/hey_client/sdk.gen.d.ts +0 -1005
- package/dist/hey_client/sdk.gen.js +0 -1438
- package/dist/hey_client/types.gen.d.ts +0 -13004
- package/dist/hey_client/types.gen.js +0 -2
- package/dist/openapi_client/models/NotificationContent.d.ts +0 -4
- package/dist/openapi_client/models/TextContent.d.ts +0 -4
- package/dist/openapi_client/models/ThinkingContent.d.ts +0 -4
- package/dist/openapi_client/models/ToolCallContent.d.ts +0 -6
- package/dist/openapi_client/models/ToolReturnContent.d.ts +0 -6
- package/dist/openapi_client/models/ToolReturnContent.js +0 -1
- /package/dist/openapi_client/models/{NotificationContent.js → ApprovalDecisionResponse.js} +0 -0
- /package/dist/openapi_client/models/{TextContent.js → FileSignedUrlRequest.js} +0 -0
- /package/dist/openapi_client/models/{ThinkingContent.js → FileSignedUrlResponse.js} +0 -0
- /package/dist/openapi_client/models/{ToolCallContent.js → FileUrlResponse.js} +0 -0
package/dist/react/useRecords.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
2
2
|
import { normalizeError, resolvePodClient, stringifyComparable } from "./utils.js";
|
|
3
|
-
export function useRecords({ client, podId, tableName, filters, sort, limit = 20, pageToken, offset,
|
|
3
|
+
export function useRecords({ client, podId, tableName, filters, sort, limit = 20, pageToken, offset, enabled = true, autoLoad = true, }) {
|
|
4
4
|
const [records, setRecords] = useState([]);
|
|
5
5
|
const [total, setTotal] = useState(0);
|
|
6
6
|
const [nextPageToken, setNextPageToken] = useState(null);
|
|
@@ -11,10 +11,8 @@ export function useRecords({ client, podId, tableName, filters, sort, limit = 20
|
|
|
11
11
|
const isEnabled = enabled && trimmedTableName.length > 0;
|
|
12
12
|
const filtersKey = stringifyComparable(filters);
|
|
13
13
|
const sortKey = stringifyComparable(sort);
|
|
14
|
-
const paramsKey = stringifyComparable(params);
|
|
15
14
|
const stableFilters = useMemo(() => filters, [filtersKey]);
|
|
16
15
|
const stableSort = useMemo(() => sort, [sortKey]);
|
|
17
|
-
const stableParams = useMemo(() => params, [paramsKey]);
|
|
18
16
|
const refresh = useCallback(async (overrides = {}, signal) => {
|
|
19
17
|
if (!isEnabled) {
|
|
20
18
|
setRecords([]);
|
|
@@ -34,9 +32,6 @@ export function useRecords({ client, podId, tableName, filters, sort, limit = 20
|
|
|
34
32
|
limit: overrides.limit ?? limit,
|
|
35
33
|
pageToken: overrides.pageToken ?? pageToken,
|
|
36
34
|
offset: overrides.offset ?? offset,
|
|
37
|
-
sortBy: overrides.sortBy ?? sortBy,
|
|
38
|
-
order: overrides.order ?? order,
|
|
39
|
-
params: overrides.params ?? stableParams,
|
|
40
35
|
});
|
|
41
36
|
if (signal?.aborted)
|
|
42
37
|
return [];
|
|
@@ -62,12 +57,9 @@ export function useRecords({ client, podId, tableName, filters, sort, limit = 20
|
|
|
62
57
|
isEnabled,
|
|
63
58
|
limit,
|
|
64
59
|
offset,
|
|
65
|
-
order,
|
|
66
60
|
pageToken,
|
|
67
61
|
podId,
|
|
68
|
-
sortBy,
|
|
69
62
|
stableFilters,
|
|
70
|
-
stableParams,
|
|
71
63
|
stableSort,
|
|
72
64
|
trimmedTableName,
|
|
73
65
|
]);
|
|
@@ -88,9 +80,6 @@ export function useRecords({ client, podId, tableName, filters, sort, limit = 20
|
|
|
88
80
|
limit: overrides.limit ?? limit,
|
|
89
81
|
pageToken: overrides.pageToken ?? nextPageToken ?? undefined,
|
|
90
82
|
offset: overrides.offset ?? (nextPageToken ? undefined : (offset ?? 0) + loadedCount),
|
|
91
|
-
sortBy: overrides.sortBy ?? sortBy,
|
|
92
|
-
order: overrides.order ?? order,
|
|
93
|
-
params: overrides.params ?? stableParams,
|
|
94
83
|
});
|
|
95
84
|
const moreRecords = (response.items ?? []);
|
|
96
85
|
setRecords((previous) => [...previous, ...moreRecords]);
|
|
@@ -106,7 +95,7 @@ export function useRecords({ client, podId, tableName, filters, sort, limit = 20
|
|
|
106
95
|
finally {
|
|
107
96
|
setIsLoadingMore(false);
|
|
108
97
|
}
|
|
109
|
-
}, [client, isEnabled, isLoading, isLoadingMore, limit, nextPageToken, offset,
|
|
98
|
+
}, [client, isEnabled, isLoading, isLoadingMore, limit, nextPageToken, offset, podId, records.length, stableFilters, stableSort, total, trimmedTableName]);
|
|
110
99
|
useEffect(() => {
|
|
111
100
|
if (!isEnabled) {
|
|
112
101
|
setRecords([]);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { LemmaClient } from "../client.js";
|
|
2
|
-
import type { Table } from "../types.js";
|
|
2
|
+
import type { RecordSort, Table } from "../types.js";
|
|
3
3
|
/**
|
|
4
4
|
* React hook for fetching records from a referencing table that point back
|
|
5
5
|
* to a specific record via a foreign key.
|
|
@@ -25,8 +25,7 @@ import type { Table } from "../types.js";
|
|
|
25
25
|
* table: "issue_history",
|
|
26
26
|
* foreignKey: "issue_id",
|
|
27
27
|
* recordId: selectedIssueId,
|
|
28
|
-
*
|
|
29
|
-
* order: "desc",
|
|
28
|
+
* sort: [{ field: "created_at", direction: "desc" }],
|
|
30
29
|
* });
|
|
31
30
|
* ```
|
|
32
31
|
*/
|
|
@@ -48,8 +47,7 @@ export interface UseReferencingRecordsOptions {
|
|
|
48
47
|
fields?: string[];
|
|
49
48
|
limit?: number;
|
|
50
49
|
offset?: number;
|
|
51
|
-
|
|
52
|
-
order?: "asc" | "desc" | string;
|
|
50
|
+
sort?: RecordSort[];
|
|
53
51
|
enabled?: boolean;
|
|
54
52
|
autoLoad?: boolean;
|
|
55
53
|
}
|
|
@@ -63,4 +61,4 @@ export interface UseReferencingRecordsResult<TRow extends Record<string, unknown
|
|
|
63
61
|
error: Error | null;
|
|
64
62
|
refresh: () => Promise<TRow[]>;
|
|
65
63
|
}
|
|
66
|
-
export declare function useReferencingRecords<TRow extends Record<string, unknown> = Record<string, unknown>>({ client, podId, table, foreignKey, recordId, fields, limit, offset,
|
|
64
|
+
export declare function useReferencingRecords<TRow extends Record<string, unknown> = Record<string, unknown>>({ client, podId, table, foreignKey, recordId, fields, limit, offset, sort, enabled, autoLoad, }: UseReferencingRecordsOptions): UseReferencingRecordsResult<TRow>;
|
|
@@ -25,7 +25,7 @@ function pickDefaultFields(table, foreignKey) {
|
|
|
25
25
|
});
|
|
26
26
|
return next.slice(0, 6);
|
|
27
27
|
}
|
|
28
|
-
export function useReferencingRecords({ client, podId, table, foreignKey, recordId = null, fields, limit = 20, offset,
|
|
28
|
+
export function useReferencingRecords({ client, podId, table, foreignKey, recordId = null, fields, limit = 20, offset, sort, enabled = true, autoLoad = true, }) {
|
|
29
29
|
const [referencedTable, setReferencedTable] = useState(null);
|
|
30
30
|
const [columns, setColumns] = useState([]);
|
|
31
31
|
const [records, setRecords] = useState([]);
|
|
@@ -36,7 +36,9 @@ export function useReferencingRecords({ client, podId, table, foreignKey, record
|
|
|
36
36
|
const trimmedTable = table.trim();
|
|
37
37
|
const trimmedRecordId = typeof recordId === "string" ? recordId.trim() : "";
|
|
38
38
|
const fieldsKey = stringifyComparable(fields);
|
|
39
|
+
const sortKey = stringifyComparable(sort);
|
|
39
40
|
const stableFields = useMemo(() => fields, [fieldsKey]);
|
|
41
|
+
const stableSort = useMemo(() => sort, [sortKey]);
|
|
40
42
|
const isEnabled = enabled && trimmedTable.length > 0 && trimmedRecordId.length > 0;
|
|
41
43
|
const refresh = useCallback(async (signal) => {
|
|
42
44
|
if (!isEnabled) {
|
|
@@ -67,8 +69,7 @@ export function useReferencingRecords({ client, podId, table, foreignKey, record
|
|
|
67
69
|
}],
|
|
68
70
|
limit,
|
|
69
71
|
offset,
|
|
70
|
-
|
|
71
|
-
order,
|
|
72
|
+
sort: stableSort,
|
|
72
73
|
});
|
|
73
74
|
if (signal?.aborted)
|
|
74
75
|
return [];
|
|
@@ -100,10 +101,9 @@ export function useReferencingRecords({ client, podId, table, foreignKey, record
|
|
|
100
101
|
isEnabled,
|
|
101
102
|
limit,
|
|
102
103
|
offset,
|
|
103
|
-
order,
|
|
104
104
|
podId,
|
|
105
|
-
sortBy,
|
|
106
105
|
stableFields,
|
|
106
|
+
stableSort,
|
|
107
107
|
trimmedRecordId,
|
|
108
108
|
trimmedTable,
|
|
109
109
|
]);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { LemmaClient } from "../client.js";
|
|
2
|
-
import type { Table } from "../types.js";
|
|
2
|
+
import type { RecordSort, Table } from "../types.js";
|
|
3
3
|
/**
|
|
4
4
|
* React hook for finding records in *other* tables that reference a given
|
|
5
5
|
* record. Starts from the parent table, discovers all tables with FK
|
|
@@ -45,8 +45,7 @@ export interface UseReverseRelatedRecordsOptions {
|
|
|
45
45
|
fields?: string[];
|
|
46
46
|
limit?: number;
|
|
47
47
|
offset?: number;
|
|
48
|
-
|
|
49
|
-
order?: "asc" | "desc" | string;
|
|
48
|
+
sort?: RecordSort[];
|
|
50
49
|
tablesLimit?: number;
|
|
51
50
|
enabled?: boolean;
|
|
52
51
|
autoLoad?: boolean;
|
|
@@ -65,4 +64,4 @@ export interface UseReverseRelatedRecordsResult<TRow extends Record<string, unkn
|
|
|
65
64
|
error: Error | null;
|
|
66
65
|
refresh: () => Promise<TRow[]>;
|
|
67
66
|
}
|
|
68
|
-
export declare function useReverseRelatedRecords<TRow extends Record<string, unknown> = Record<string, unknown>>({ client, podId, tableName, recordId, relation, fields, limit, offset,
|
|
67
|
+
export declare function useReverseRelatedRecords<TRow extends Record<string, unknown> = Record<string, unknown>>({ client, podId, tableName, recordId, relation, fields, limit, offset, sort, tablesLimit, enabled, autoLoad, }: UseReverseRelatedRecordsOptions): UseReverseRelatedRecordsResult<TRow>;
|
|
@@ -26,7 +26,7 @@ function pickDefaultFields(table, foreignKey) {
|
|
|
26
26
|
});
|
|
27
27
|
return next.slice(0, 6);
|
|
28
28
|
}
|
|
29
|
-
export function useReverseRelatedRecords({ client, podId, tableName, recordId = null, relation = null, fields, limit = 20, offset,
|
|
29
|
+
export function useReverseRelatedRecords({ client, podId, tableName, recordId = null, relation = null, fields, limit = 20, offset, sort, tablesLimit = 100, enabled = true, autoLoad = true, }) {
|
|
30
30
|
const [parentTable, setParentTable] = useState(null);
|
|
31
31
|
const [relatedTable, setRelatedTable] = useState(null);
|
|
32
32
|
const [parentRecord, setParentRecord] = useState(null);
|
|
@@ -42,8 +42,10 @@ export function useReverseRelatedRecords({ client, podId, tableName, recordId =
|
|
|
42
42
|
const trimmedRecordId = typeof recordId === "string" ? recordId.trim() : "";
|
|
43
43
|
const relationKey = stringifyComparable(relation);
|
|
44
44
|
const fieldsKey = stringifyComparable(fields);
|
|
45
|
+
const sortKey = stringifyComparable(sort);
|
|
45
46
|
const stableRelation = useMemo(() => relation, [relationKey]);
|
|
46
47
|
const stableFields = useMemo(() => fields, [fieldsKey]);
|
|
48
|
+
const stableSort = useMemo(() => sort, [sortKey]);
|
|
47
49
|
const isEnabled = enabled && trimmedTableName.length > 0 && trimmedRecordId.length > 0;
|
|
48
50
|
const refresh = useCallback(async (signal) => {
|
|
49
51
|
if (!isEnabled) {
|
|
@@ -130,8 +132,7 @@ export function useReverseRelatedRecords({ client, podId, tableName, recordId =
|
|
|
130
132
|
}],
|
|
131
133
|
limit,
|
|
132
134
|
offset,
|
|
133
|
-
|
|
134
|
-
order,
|
|
135
|
+
sort: stableSort,
|
|
135
136
|
});
|
|
136
137
|
if (signal?.aborted)
|
|
137
138
|
return [];
|
|
@@ -162,11 +163,10 @@ export function useReverseRelatedRecords({ client, podId, tableName, recordId =
|
|
|
162
163
|
isEnabled,
|
|
163
164
|
limit,
|
|
164
165
|
offset,
|
|
165
|
-
order,
|
|
166
166
|
podId,
|
|
167
|
-
sortBy,
|
|
168
167
|
stableFields,
|
|
169
168
|
stableRelation,
|
|
169
|
+
stableSort,
|
|
170
170
|
tablesLimit,
|
|
171
171
|
trimmedRecordId,
|
|
172
172
|
trimmedTableName,
|
package/dist/run-utils.d.ts
CHANGED
|
@@ -12,4 +12,28 @@ export declare function isTerminalFlowStatus(status: unknown, options?: {
|
|
|
12
12
|
}): boolean;
|
|
13
13
|
export declare function sleep(ms: number, signal?: AbortSignal): Promise<void>;
|
|
14
14
|
export declare function nextBackoffDelay(attempt: number, options?: BackoffOptions): number;
|
|
15
|
+
/**
|
|
16
|
+
* Statuses worth retrying with backoff. Deliberately conservative: 429 is an
|
|
17
|
+
* explicit "back off", and 502/503/504 are gateway errors where the request
|
|
18
|
+
* usually never reached the handler — so retrying is safe even for writes.
|
|
19
|
+
* 500 is excluded (it may indicate a partial side effect).
|
|
20
|
+
*/
|
|
21
|
+
export declare const RETRYABLE_STATUS: ReadonlySet<number>;
|
|
22
|
+
/** Parse a server `Retry-After` header (delta-seconds or HTTP-date) into ms,
|
|
23
|
+
* capped at 30s. Returns null when the header is absent or unparseable. */
|
|
24
|
+
export declare function serverRetryAfterMs(retryAfter: string | null | undefined): number | null;
|
|
25
|
+
/** Resolve a backoff delay, honoring a server `Retry-After` header when present. */
|
|
26
|
+
export declare function retryAfterMs(retryAfter: string | null | undefined, attempt: number): number;
|
|
27
|
+
/** Equal jitter: keep half the delay fixed and randomize the other half, so the
|
|
28
|
+
* result lands in `[delay/2, delay]`. Spreads correlated retries (thundering
|
|
29
|
+
* herd) without ever waiting longer than the computed backoff. */
|
|
30
|
+
export declare function applyJitter(delayMs: number, random?: () => number): number;
|
|
31
|
+
/**
|
|
32
|
+
* Single source of truth for the retry decision shared by the hand-written
|
|
33
|
+
* `HttpClient` and the generated-client adapter. Returns the number of ms to
|
|
34
|
+
* wait before retrying, or `null` when the status is non-retryable or retries
|
|
35
|
+
* are exhausted. A server-advised `Retry-After` is honored verbatim (no jitter);
|
|
36
|
+
* the computed exponential backoff gets equal jitter.
|
|
37
|
+
*/
|
|
38
|
+
export declare function retryDelayForStatus(status: number, attempt: number, maxRetries: number, retryAfterHeader: string | null | undefined, random?: () => number): number | null;
|
|
15
39
|
export {};
|
package/dist/run-utils.js
CHANGED
|
@@ -50,3 +50,57 @@ export function nextBackoffDelay(attempt, options = {}) {
|
|
|
50
50
|
const delay = Math.round(baseMs * Math.pow(factor, safeAttempt));
|
|
51
51
|
return Math.min(Math.max(baseMs, delay), maxMs);
|
|
52
52
|
}
|
|
53
|
+
/**
|
|
54
|
+
* Statuses worth retrying with backoff. Deliberately conservative: 429 is an
|
|
55
|
+
* explicit "back off", and 502/503/504 are gateway errors where the request
|
|
56
|
+
* usually never reached the handler — so retrying is safe even for writes.
|
|
57
|
+
* 500 is excluded (it may indicate a partial side effect).
|
|
58
|
+
*/
|
|
59
|
+
export const RETRYABLE_STATUS = new Set([429, 502, 503, 504]);
|
|
60
|
+
/** Parse a server `Retry-After` header (delta-seconds or HTTP-date) into ms,
|
|
61
|
+
* capped at 30s. Returns null when the header is absent or unparseable. */
|
|
62
|
+
export function serverRetryAfterMs(retryAfter) {
|
|
63
|
+
if (!retryAfter) {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
const seconds = Number(retryAfter);
|
|
67
|
+
if (Number.isFinite(seconds) && seconds >= 0) {
|
|
68
|
+
return Math.min(seconds * 1000, 30_000);
|
|
69
|
+
}
|
|
70
|
+
const dateMs = Date.parse(retryAfter);
|
|
71
|
+
if (!Number.isNaN(dateMs)) {
|
|
72
|
+
return Math.max(0, Math.min(dateMs - Date.now(), 30_000));
|
|
73
|
+
}
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
/** Resolve a backoff delay, honoring a server `Retry-After` header when present. */
|
|
77
|
+
export function retryAfterMs(retryAfter, attempt) {
|
|
78
|
+
return serverRetryAfterMs(retryAfter) ?? nextBackoffDelay(attempt);
|
|
79
|
+
}
|
|
80
|
+
/** Equal jitter: keep half the delay fixed and randomize the other half, so the
|
|
81
|
+
* result lands in `[delay/2, delay]`. Spreads correlated retries (thundering
|
|
82
|
+
* herd) without ever waiting longer than the computed backoff. */
|
|
83
|
+
export function applyJitter(delayMs, random = Math.random) {
|
|
84
|
+
if (!Number.isFinite(delayMs) || delayMs <= 0) {
|
|
85
|
+
return 0;
|
|
86
|
+
}
|
|
87
|
+
const half = delayMs / 2;
|
|
88
|
+
return Math.round(half + random() * half);
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Single source of truth for the retry decision shared by the hand-written
|
|
92
|
+
* `HttpClient` and the generated-client adapter. Returns the number of ms to
|
|
93
|
+
* wait before retrying, or `null` when the status is non-retryable or retries
|
|
94
|
+
* are exhausted. A server-advised `Retry-After` is honored verbatim (no jitter);
|
|
95
|
+
* the computed exponential backoff gets equal jitter.
|
|
96
|
+
*/
|
|
97
|
+
export function retryDelayForStatus(status, attempt, maxRetries, retryAfterHeader, random = Math.random) {
|
|
98
|
+
if (!RETRYABLE_STATUS.has(status) || attempt >= maxRetries) {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
const serverMs = serverRetryAfterMs(retryAfterHeader);
|
|
102
|
+
if (serverMs !== null) {
|
|
103
|
+
return serverMs;
|
|
104
|
+
}
|
|
105
|
+
return applyJitter(nextBackoffDelay(attempt), random);
|
|
106
|
+
}
|
package/dist/types.d.ts
CHANGED
|
@@ -38,9 +38,6 @@ export interface ListRecordsOptions {
|
|
|
38
38
|
limit?: number;
|
|
39
39
|
pageToken?: string;
|
|
40
40
|
offset?: number;
|
|
41
|
-
sortBy?: string;
|
|
42
|
-
order?: "asc" | "desc" | string;
|
|
43
|
-
params?: Record<string, string | number | boolean | undefined | null>;
|
|
44
41
|
}
|
|
45
42
|
export interface RunFunctionOptions {
|
|
46
43
|
/** Input payload for the function */
|
|
@@ -62,17 +59,26 @@ export type Conversation = GeneratedConversationResponse & {
|
|
|
62
59
|
model?: ConversationModel | null;
|
|
63
60
|
status?: string | null;
|
|
64
61
|
};
|
|
62
|
+
/** Discriminator for the flat message shape (replaces the old nested content union). */
|
|
63
|
+
export type MessageKind = "text" | "thinking" | "notification" | "tool_call" | "tool_return";
|
|
65
64
|
export interface ConversationMessageResponse {
|
|
66
65
|
id: string;
|
|
67
66
|
role: string;
|
|
68
|
-
|
|
67
|
+
kind: MessageKind;
|
|
68
|
+
/** Body for text / thinking / notification messages. */
|
|
69
|
+
text?: string | null;
|
|
70
|
+
/** Set on tool_call / tool_return messages. */
|
|
71
|
+
tool_name?: string | null;
|
|
72
|
+
tool_call_id?: string | null;
|
|
73
|
+
/** Inputs for a tool_call (arbitrary JSON). */
|
|
74
|
+
tool_args?: unknown;
|
|
75
|
+
/** Output for a tool_return (arbitrary JSON). */
|
|
76
|
+
tool_result?: unknown;
|
|
69
77
|
created_at: string;
|
|
70
78
|
conversation_id?: string;
|
|
71
79
|
sequence?: number;
|
|
72
80
|
agent_run_id?: string | null;
|
|
73
81
|
metadata?: Record<string, unknown> | null;
|
|
74
|
-
tool_call_id?: string | null;
|
|
75
|
-
tool_name?: string | null;
|
|
76
82
|
}
|
|
77
83
|
export type ConversationMessage = ConversationMessageResponse;
|
|
78
84
|
export type FunctionRun = FunctionRunResponse;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare const SDK_VERSION = "0.3.0";
|
|
2
|
+
/** Sent as `X-Lemma-Client` on every request so the backend can log which client
|
|
3
|
+
* + version hit an endpoint (User-Agent is a forbidden header in browser fetch). */
|
|
4
|
+
export declare const CLIENT_HEADER_NAME = "X-Lemma-Client";
|
|
5
|
+
export declare const CLIENT_HEADER_VALUE = "lemma-sdk-ts/0.3.0";
|
package/dist/version.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// Keep SDK_VERSION in sync with package.json "version". The CI codegen/drift
|
|
2
|
+
// gate (workstream A) asserts they match so this can't silently drift.
|
|
3
|
+
export const SDK_VERSION = "0.3.0";
|
|
4
|
+
/** Sent as `X-Lemma-Client` on every request so the backend can log which client
|
|
5
|
+
* + version hit an endpoint (User-Agent is a forbidden header in browser fetch). */
|
|
6
|
+
export const CLIENT_HEADER_NAME = "X-Lemma-Client";
|
|
7
|
+
export const CLIENT_HEADER_VALUE = `lemma-sdk-ts/${SDK_VERSION}`;
|
package/package.json
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lemma-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Official TypeScript SDK for Lemma APIs, optimized around pod-scoped workflows",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"author": "Lemma",
|
|
5
7
|
"type": "module",
|
|
6
8
|
"main": "dist/index.js",
|
|
7
9
|
"types": "dist/index.d.ts",
|
|
@@ -44,9 +46,9 @@
|
|
|
44
46
|
],
|
|
45
47
|
"scripts": {
|
|
46
48
|
"generate:client": "./scripts/generate_openapi_client.sh",
|
|
47
|
-
"generate:client:hey": "LEMMA_TS_GENERATOR=hey ./scripts/generate_openapi_client.sh",
|
|
48
49
|
"build": "npm run clean && tsc -p tsconfig.json && npm run build:bundle",
|
|
49
|
-
"build:bundle": "
|
|
50
|
+
"build:bundle": "node ./scripts/build_browser_bundle.mjs",
|
|
51
|
+
"test": "npm run build:bundle && vitest run",
|
|
50
52
|
"clean": "node -e \"require('fs').rmSync('dist', { recursive: true, force: true, maxRetries: 10, retryDelay: 100 })\"",
|
|
51
53
|
"registry:build": "shadcn build ./registry.json -o ./public/r",
|
|
52
54
|
"registry:check": "npm run registry:build && node ./scripts/check_registry_blocks.mjs",
|
|
@@ -65,10 +67,13 @@
|
|
|
65
67
|
"supertokens-web-js": "^0.16.0"
|
|
66
68
|
},
|
|
67
69
|
"devDependencies": {
|
|
68
|
-
"@
|
|
70
|
+
"@types/node": "^24.13.2",
|
|
69
71
|
"@types/react": "^19.2.14",
|
|
72
|
+
"esbuild": "^0.28.1",
|
|
73
|
+
"jsdom": "^24.1.1",
|
|
70
74
|
"openapi-typescript-codegen": "^0.29.0",
|
|
71
75
|
"shadcn": "^4.2.0",
|
|
72
|
-
"typescript": "^5.6.3"
|
|
76
|
+
"typescript": "^5.6.3",
|
|
77
|
+
"vitest": "^2.0.5"
|
|
73
78
|
}
|
|
74
79
|
}
|
|
@@ -1,216 +0,0 @@
|
|
|
1
|
-
// This file is auto-generated by @hey-api/openapi-ts
|
|
2
|
-
import { createSseClient } from '../core/serverSentEvents.gen';
|
|
3
|
-
import { getValidRequestBody } from '../core/utils.gen';
|
|
4
|
-
import { buildUrl, createConfig, createInterceptors, getParseAs, mergeConfigs, mergeHeaders, setAuthParams, } from './utils.gen';
|
|
5
|
-
export const createClient = (config = {}) => {
|
|
6
|
-
let _config = mergeConfigs(createConfig(), config);
|
|
7
|
-
const getConfig = () => ({ ..._config });
|
|
8
|
-
const setConfig = (config) => {
|
|
9
|
-
_config = mergeConfigs(_config, config);
|
|
10
|
-
return getConfig();
|
|
11
|
-
};
|
|
12
|
-
const interceptors = createInterceptors();
|
|
13
|
-
const beforeRequest = async (options) => {
|
|
14
|
-
const opts = {
|
|
15
|
-
..._config,
|
|
16
|
-
...options,
|
|
17
|
-
fetch: options.fetch ?? _config.fetch ?? globalThis.fetch,
|
|
18
|
-
headers: mergeHeaders(_config.headers, options.headers),
|
|
19
|
-
serializedBody: undefined,
|
|
20
|
-
};
|
|
21
|
-
if (opts.security) {
|
|
22
|
-
await setAuthParams(opts);
|
|
23
|
-
}
|
|
24
|
-
if (opts.requestValidator) {
|
|
25
|
-
await opts.requestValidator(opts);
|
|
26
|
-
}
|
|
27
|
-
if (opts.body !== undefined && opts.bodySerializer) {
|
|
28
|
-
opts.serializedBody = opts.bodySerializer(opts.body);
|
|
29
|
-
}
|
|
30
|
-
// remove Content-Type header if body is empty to avoid sending invalid requests
|
|
31
|
-
if (opts.body === undefined || opts.serializedBody === '') {
|
|
32
|
-
opts.headers.delete('Content-Type');
|
|
33
|
-
}
|
|
34
|
-
const resolvedOpts = opts;
|
|
35
|
-
const url = buildUrl(resolvedOpts);
|
|
36
|
-
return { opts: resolvedOpts, url };
|
|
37
|
-
};
|
|
38
|
-
const request = async (options) => {
|
|
39
|
-
const throwOnError = options.throwOnError ?? _config.throwOnError;
|
|
40
|
-
const responseStyle = options.responseStyle ?? _config.responseStyle;
|
|
41
|
-
let request;
|
|
42
|
-
let response;
|
|
43
|
-
try {
|
|
44
|
-
const { opts, url } = await beforeRequest(options);
|
|
45
|
-
const requestInit = {
|
|
46
|
-
redirect: 'follow',
|
|
47
|
-
...opts,
|
|
48
|
-
body: getValidRequestBody(opts),
|
|
49
|
-
};
|
|
50
|
-
request = new Request(url, requestInit);
|
|
51
|
-
for (const fn of interceptors.request.fns) {
|
|
52
|
-
if (fn) {
|
|
53
|
-
request = await fn(request, opts);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
// fetch must be assigned here, otherwise it would throw the error:
|
|
57
|
-
// TypeError: Failed to execute 'fetch' on 'Window': Illegal invocation
|
|
58
|
-
const _fetch = opts.fetch;
|
|
59
|
-
response = await _fetch(request);
|
|
60
|
-
for (const fn of interceptors.response.fns) {
|
|
61
|
-
if (fn) {
|
|
62
|
-
response = await fn(response, request, opts);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
const result = {
|
|
66
|
-
request,
|
|
67
|
-
response,
|
|
68
|
-
};
|
|
69
|
-
if (response.ok) {
|
|
70
|
-
const parseAs = (opts.parseAs === 'auto'
|
|
71
|
-
? getParseAs(response.headers.get('Content-Type'))
|
|
72
|
-
: opts.parseAs) ?? 'json';
|
|
73
|
-
if (response.status === 204 || response.headers.get('Content-Length') === '0') {
|
|
74
|
-
let emptyData;
|
|
75
|
-
switch (parseAs) {
|
|
76
|
-
case 'arrayBuffer':
|
|
77
|
-
case 'blob':
|
|
78
|
-
case 'text':
|
|
79
|
-
emptyData = await response[parseAs]();
|
|
80
|
-
break;
|
|
81
|
-
case 'formData':
|
|
82
|
-
emptyData = new FormData();
|
|
83
|
-
break;
|
|
84
|
-
case 'stream':
|
|
85
|
-
emptyData = response.body;
|
|
86
|
-
break;
|
|
87
|
-
case 'json':
|
|
88
|
-
default:
|
|
89
|
-
emptyData = {};
|
|
90
|
-
break;
|
|
91
|
-
}
|
|
92
|
-
return opts.responseStyle === 'data'
|
|
93
|
-
? emptyData
|
|
94
|
-
: {
|
|
95
|
-
data: emptyData,
|
|
96
|
-
...result,
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
let data;
|
|
100
|
-
switch (parseAs) {
|
|
101
|
-
case 'arrayBuffer':
|
|
102
|
-
case 'blob':
|
|
103
|
-
case 'formData':
|
|
104
|
-
case 'text':
|
|
105
|
-
data = await response[parseAs]();
|
|
106
|
-
break;
|
|
107
|
-
case 'json': {
|
|
108
|
-
// Some servers return 200 with no Content-Length and empty body.
|
|
109
|
-
// response.json() would throw; read as text and parse if non-empty.
|
|
110
|
-
const text = await response.text();
|
|
111
|
-
data = text ? JSON.parse(text) : {};
|
|
112
|
-
break;
|
|
113
|
-
}
|
|
114
|
-
case 'stream':
|
|
115
|
-
return opts.responseStyle === 'data'
|
|
116
|
-
? response.body
|
|
117
|
-
: {
|
|
118
|
-
data: response.body,
|
|
119
|
-
...result,
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
if (parseAs === 'json') {
|
|
123
|
-
if (opts.responseValidator) {
|
|
124
|
-
await opts.responseValidator(data);
|
|
125
|
-
}
|
|
126
|
-
if (opts.responseTransformer) {
|
|
127
|
-
data = await opts.responseTransformer(data);
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
return opts.responseStyle === 'data'
|
|
131
|
-
? data
|
|
132
|
-
: {
|
|
133
|
-
data,
|
|
134
|
-
...result,
|
|
135
|
-
};
|
|
136
|
-
}
|
|
137
|
-
const textError = await response.text();
|
|
138
|
-
let jsonError;
|
|
139
|
-
try {
|
|
140
|
-
jsonError = JSON.parse(textError);
|
|
141
|
-
}
|
|
142
|
-
catch {
|
|
143
|
-
// noop
|
|
144
|
-
}
|
|
145
|
-
throw jsonError ?? textError;
|
|
146
|
-
}
|
|
147
|
-
catch (error) {
|
|
148
|
-
let finalError = error;
|
|
149
|
-
for (const fn of interceptors.error.fns) {
|
|
150
|
-
if (fn) {
|
|
151
|
-
finalError = await fn(finalError, response, request, options);
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
finalError = finalError || {};
|
|
155
|
-
if (throwOnError) {
|
|
156
|
-
throw finalError;
|
|
157
|
-
}
|
|
158
|
-
// TODO: we probably want to return error and improve types
|
|
159
|
-
return responseStyle === 'data'
|
|
160
|
-
? undefined
|
|
161
|
-
: {
|
|
162
|
-
error: finalError,
|
|
163
|
-
request,
|
|
164
|
-
response,
|
|
165
|
-
};
|
|
166
|
-
}
|
|
167
|
-
};
|
|
168
|
-
const makeMethodFn = (method) => (options) => request({ ...options, method });
|
|
169
|
-
const makeSseFn = (method) => async (options) => {
|
|
170
|
-
const { opts, url } = await beforeRequest(options);
|
|
171
|
-
return createSseClient({
|
|
172
|
-
...opts,
|
|
173
|
-
body: opts.body,
|
|
174
|
-
method,
|
|
175
|
-
onRequest: async (url, init) => {
|
|
176
|
-
let request = new Request(url, init);
|
|
177
|
-
for (const fn of interceptors.request.fns) {
|
|
178
|
-
if (fn) {
|
|
179
|
-
request = await fn(request, opts);
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
return request;
|
|
183
|
-
},
|
|
184
|
-
serializedBody: getValidRequestBody(opts),
|
|
185
|
-
url,
|
|
186
|
-
});
|
|
187
|
-
};
|
|
188
|
-
const _buildUrl = (options) => buildUrl({ ..._config, ...options });
|
|
189
|
-
return {
|
|
190
|
-
buildUrl: _buildUrl,
|
|
191
|
-
connect: makeMethodFn('CONNECT'),
|
|
192
|
-
delete: makeMethodFn('DELETE'),
|
|
193
|
-
get: makeMethodFn('GET'),
|
|
194
|
-
getConfig,
|
|
195
|
-
head: makeMethodFn('HEAD'),
|
|
196
|
-
interceptors,
|
|
197
|
-
options: makeMethodFn('OPTIONS'),
|
|
198
|
-
patch: makeMethodFn('PATCH'),
|
|
199
|
-
post: makeMethodFn('POST'),
|
|
200
|
-
put: makeMethodFn('PUT'),
|
|
201
|
-
request,
|
|
202
|
-
setConfig,
|
|
203
|
-
sse: {
|
|
204
|
-
connect: makeSseFn('CONNECT'),
|
|
205
|
-
delete: makeSseFn('DELETE'),
|
|
206
|
-
get: makeSseFn('GET'),
|
|
207
|
-
head: makeSseFn('HEAD'),
|
|
208
|
-
options: makeSseFn('OPTIONS'),
|
|
209
|
-
patch: makeSseFn('PATCH'),
|
|
210
|
-
post: makeSseFn('POST'),
|
|
211
|
-
put: makeSseFn('PUT'),
|
|
212
|
-
trace: makeSseFn('TRACE'),
|
|
213
|
-
},
|
|
214
|
-
trace: makeMethodFn('TRACE'),
|
|
215
|
-
};
|
|
216
|
-
};
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
export type { Auth } from '../core/auth.gen';
|
|
2
|
-
export type { QuerySerializerOptions } from '../core/bodySerializer.gen';
|
|
3
|
-
export { formDataBodySerializer, jsonBodySerializer, urlSearchParamsBodySerializer, } from '../core/bodySerializer.gen';
|
|
4
|
-
export { buildClientParams } from '../core/params.gen';
|
|
5
|
-
export { serializeQueryKeyValue } from '../core/queryKeySerializer.gen';
|
|
6
|
-
export type { ServerSentEventsResult } from '../core/serverSentEvents.gen';
|
|
7
|
-
export type { ClientMeta } from '../core/types.gen';
|
|
8
|
-
export { createClient } from './client.gen';
|
|
9
|
-
export type { Client, ClientOptions, Config, CreateClientConfig, Options, RequestOptions, RequestResult, ResolvedRequestOptions, ResponseStyle, TDataShape, } from './types.gen';
|
|
10
|
-
export { createConfig, mergeHeaders } from './utils.gen';
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
// This file is auto-generated by @hey-api/openapi-ts
|
|
2
|
-
export { formDataBodySerializer, jsonBodySerializer, urlSearchParamsBodySerializer, } from '../core/bodySerializer.gen';
|
|
3
|
-
export { buildClientParams } from '../core/params.gen';
|
|
4
|
-
export { serializeQueryKeyValue } from '../core/queryKeySerializer.gen';
|
|
5
|
-
export { createClient } from './client.gen';
|
|
6
|
-
export { createConfig, mergeHeaders } from './utils.gen';
|