@osdk/react 0.17.0-main-5dc557e9e321d23e8e150e8015c41ebe3b6f387c → 0.17.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 +19 -35
- package/CHANGELOG.md +8 -7
- package/build/browser/aip/chatStore.js +67 -0
- package/build/browser/aip/chatStore.js.map +1 -0
- package/build/browser/aip/chatStream.js +155 -0
- package/build/browser/aip/chatStream.js.map +1 -0
- package/build/browser/aip/useChat.js +243 -0
- package/build/browser/aip/useChat.js.map +1 -0
- package/build/browser/index.js +14 -1
- package/build/browser/index.js.map +1 -1
- package/build/browser/new/{OsdkContext2.js → OsdkContext.js} +4 -4
- package/build/browser/new/OsdkContext.js.map +1 -0
- package/build/browser/new/{OsdkProvider2.js → OsdkProvider.js} +7 -13
- package/build/browser/new/OsdkProvider.js.map +1 -0
- package/build/browser/new/core/useStableObjectSet.js +1 -1
- package/build/browser/new/core/useStableObjectSet.js.map +1 -1
- package/build/browser/new/createCompositeExternalStore.js.map +1 -1
- package/build/browser/new/makeExternalStore.js.map +1 -1
- package/build/browser/new/platform-apis/admin/useCbacBanner.js +2 -2
- package/build/browser/new/platform-apis/admin/useCbacBanner.js.map +1 -1
- package/build/browser/new/platform-apis/admin/useCbacMarkingRestrictions.js +2 -2
- package/build/browser/new/platform-apis/admin/useCbacMarkingRestrictions.js.map +1 -1
- package/build/browser/new/platform-apis/admin/useCurrentFoundryUser.js +2 -2
- package/build/browser/new/platform-apis/admin/useCurrentFoundryUser.js.map +1 -1
- package/build/browser/new/platform-apis/admin/useFoundryUser.js +2 -2
- package/build/browser/new/platform-apis/admin/useFoundryUser.js.map +1 -1
- package/build/browser/new/platform-apis/admin/useFoundryUsersList.js +2 -2
- package/build/browser/new/platform-apis/admin/useFoundryUsersList.js.map +1 -1
- package/build/browser/new/platform-apis/admin/useMarkingCategories.js +2 -2
- package/build/browser/new/platform-apis/admin/useMarkingCategories.js.map +1 -1
- package/build/browser/new/platform-apis/admin/useMarkings.js +2 -2
- package/build/browser/new/platform-apis/admin/useMarkings.js.map +1 -1
- package/build/browser/new/platform-apis/admin/useUserMarkings.js +2 -2
- package/build/browser/new/platform-apis/admin/useUserMarkings.js.map +1 -1
- package/build/browser/new/shapes/derivedLinksStore.js.map +1 -1
- package/build/browser/new/shapes/types.js.map +1 -1
- package/build/browser/new/useDevToolsClient.js.map +1 -1
- package/build/browser/new/useLinks.js +5 -3
- package/build/browser/new/useLinks.js.map +1 -1
- package/build/browser/new/useObjectSet.js +3 -3
- package/build/browser/new/useObjectSet.js.map +1 -1
- package/build/browser/new/useOsdkAction.js +2 -2
- package/build/browser/new/useOsdkAction.js.map +1 -1
- package/build/browser/new/useOsdkAggregation.js +3 -3
- package/build/browser/new/useOsdkAggregation.js.map +1 -1
- package/build/browser/new/useOsdkFunction.js +3 -3
- package/build/browser/new/useOsdkFunction.js.map +1 -1
- package/build/browser/new/useOsdkFunctions.js +2 -2
- package/build/browser/new/useOsdkFunctions.js.map +1 -1
- package/build/browser/new/useOsdkObject.js +2 -2
- package/build/browser/new/useOsdkObject.js.map +1 -1
- package/build/browser/new/useOsdkObjects.js +2 -2
- package/build/browser/new/useOsdkObjects.js.map +1 -1
- package/build/browser/public/devtools-registry.js.map +1 -1
- package/build/browser/public/experimental/admin.js +27 -0
- package/build/browser/public/experimental/admin.js.map +1 -1
- package/build/browser/{OsdkProvider.js → public/experimental/aip.js} +3 -14
- package/build/browser/public/experimental/aip.js.map +1 -0
- package/build/browser/public/experimental.js +58 -2
- package/build/browser/public/experimental.js.map +1 -1
- package/build/browser/public/platform-apis.js +25 -0
- package/build/browser/public/platform-apis.js.map +1 -0
- package/build/browser/public/testing.js +61 -0
- package/build/browser/public/testing.js.map +1 -0
- package/build/browser/useObservableClient.js +41 -0
- package/build/browser/useObservableClient.js.map +1 -0
- package/build/browser/useOsdkClient.js +1 -5
- package/build/browser/useOsdkClient.js.map +1 -1
- package/build/browser/util/UserAgent.js +1 -1
- package/build/browser/util/UserAgent.js.map +1 -1
- package/build/browser/utils/usePlatformQuery.js.map +1 -1
- package/build/cjs/chunk-6XVB5CWK.cjs +875 -0
- package/build/cjs/chunk-6XVB5CWK.cjs.map +1 -0
- package/build/cjs/{chunk-2Y5CIQPC.cjs → chunk-DO3NFBKN.cjs} +6 -6
- package/build/cjs/chunk-DO3NFBKN.cjs.map +1 -0
- package/build/cjs/chunk-HJHKH4B6.cjs +300 -0
- package/build/cjs/chunk-HJHKH4B6.cjs.map +1 -0
- package/build/cjs/index.cjs +65 -14
- package/build/cjs/index.cjs.map +1 -1
- package/build/cjs/index.d.cts +25 -8
- package/build/cjs/public/devtools-registry.d.cts +1 -1
- package/build/cjs/public/experimental/admin.cjs +35 -293
- package/build/cjs/public/experimental/admin.cjs.map +1 -1
- package/build/cjs/public/experimental/admin.d.cts +3 -275
- package/build/cjs/public/experimental/aip.cjs +389 -0
- package/build/cjs/public/experimental/aip.cjs.map +1 -0
- package/build/cjs/public/experimental/aip.d.cts +83 -0
- package/build/cjs/public/experimental.cjs +53 -847
- package/build/cjs/public/experimental.cjs.map +1 -1
- package/build/cjs/public/experimental.d.cts +41 -16
- package/build/cjs/public/platform-apis.cjs +42 -0
- package/build/cjs/public/platform-apis.cjs.map +1 -0
- package/build/cjs/public/platform-apis.d.cts +275 -0
- package/build/cjs/public/testing.cjs +55 -0
- package/build/cjs/public/testing.cjs.map +1 -0
- package/build/cjs/public/testing.d.cts +27 -0
- package/build/esm/aip/chatStore.js +67 -0
- package/build/esm/aip/chatStore.js.map +1 -0
- package/build/esm/aip/chatStream.js +155 -0
- package/build/esm/aip/chatStream.js.map +1 -0
- package/build/esm/aip/useChat.js +243 -0
- package/build/esm/aip/useChat.js.map +1 -0
- package/build/esm/index.js +14 -1
- package/build/esm/index.js.map +1 -1
- package/build/esm/new/{OsdkContext2.js → OsdkContext.js} +4 -4
- package/build/esm/new/OsdkContext.js.map +1 -0
- package/build/esm/new/{OsdkProvider2.js → OsdkProvider.js} +7 -13
- package/build/esm/new/OsdkProvider.js.map +1 -0
- package/build/esm/new/core/useStableObjectSet.js +1 -1
- package/build/esm/new/core/useStableObjectSet.js.map +1 -1
- package/build/esm/new/createCompositeExternalStore.js.map +1 -1
- package/build/esm/new/makeExternalStore.js.map +1 -1
- package/build/esm/new/platform-apis/admin/useCbacBanner.js +2 -2
- package/build/esm/new/platform-apis/admin/useCbacBanner.js.map +1 -1
- package/build/esm/new/platform-apis/admin/useCbacMarkingRestrictions.js +2 -2
- package/build/esm/new/platform-apis/admin/useCbacMarkingRestrictions.js.map +1 -1
- package/build/esm/new/platform-apis/admin/useCurrentFoundryUser.js +2 -2
- package/build/esm/new/platform-apis/admin/useCurrentFoundryUser.js.map +1 -1
- package/build/esm/new/platform-apis/admin/useFoundryUser.js +2 -2
- package/build/esm/new/platform-apis/admin/useFoundryUser.js.map +1 -1
- package/build/esm/new/platform-apis/admin/useFoundryUsersList.js +2 -2
- package/build/esm/new/platform-apis/admin/useFoundryUsersList.js.map +1 -1
- package/build/esm/new/platform-apis/admin/useMarkingCategories.js +2 -2
- package/build/esm/new/platform-apis/admin/useMarkingCategories.js.map +1 -1
- package/build/esm/new/platform-apis/admin/useMarkings.js +2 -2
- package/build/esm/new/platform-apis/admin/useMarkings.js.map +1 -1
- package/build/esm/new/platform-apis/admin/useUserMarkings.js +2 -2
- package/build/esm/new/platform-apis/admin/useUserMarkings.js.map +1 -1
- package/build/esm/new/shapes/derivedLinksStore.js.map +1 -1
- package/build/esm/new/shapes/types.js.map +1 -1
- package/build/esm/new/useDevToolsClient.js.map +1 -1
- package/build/esm/new/useLinks.js +5 -3
- package/build/esm/new/useLinks.js.map +1 -1
- package/build/esm/new/useObjectSet.js +3 -3
- package/build/esm/new/useObjectSet.js.map +1 -1
- package/build/esm/new/useOsdkAction.js +2 -2
- package/build/esm/new/useOsdkAction.js.map +1 -1
- package/build/esm/new/useOsdkAggregation.js +3 -3
- package/build/esm/new/useOsdkAggregation.js.map +1 -1
- package/build/esm/new/useOsdkFunction.js +3 -3
- package/build/esm/new/useOsdkFunction.js.map +1 -1
- package/build/esm/new/useOsdkFunctions.js +2 -2
- package/build/esm/new/useOsdkFunctions.js.map +1 -1
- package/build/esm/new/useOsdkObject.js +2 -2
- package/build/esm/new/useOsdkObject.js.map +1 -1
- package/build/esm/new/useOsdkObjects.js +2 -2
- package/build/esm/new/useOsdkObjects.js.map +1 -1
- package/build/esm/public/devtools-registry.js.map +1 -1
- package/build/esm/public/experimental/admin.js +27 -0
- package/build/esm/public/experimental/admin.js.map +1 -1
- package/build/esm/{OsdkProvider.js → public/experimental/aip.js} +3 -14
- package/build/esm/public/experimental/aip.js.map +1 -0
- package/build/esm/public/experimental.js +58 -2
- package/build/esm/public/experimental.js.map +1 -1
- package/build/esm/public/platform-apis.js +25 -0
- package/build/esm/public/platform-apis.js.map +1 -0
- package/build/esm/public/testing.js +61 -0
- package/build/esm/public/testing.js.map +1 -0
- package/build/esm/useObservableClient.js +41 -0
- package/build/esm/useObservableClient.js.map +1 -0
- package/build/esm/useOsdkClient.js +1 -5
- package/build/esm/useOsdkClient.js.map +1 -1
- package/build/esm/util/UserAgent.js +1 -1
- package/build/esm/util/UserAgent.js.map +1 -1
- package/build/esm/utils/usePlatformQuery.js.map +1 -1
- package/build/types/aip/chatStore.d.ts +31 -0
- package/build/types/aip/chatStore.d.ts.map +1 -0
- package/build/types/aip/chatStream.d.ts +20 -0
- package/build/types/aip/chatStream.d.ts.map +1 -0
- package/build/types/aip/useChat.d.ts +79 -0
- package/build/types/aip/useChat.d.ts.map +1 -0
- package/build/types/index.d.ts +20 -1
- package/build/types/index.d.ts.map +1 -1
- package/build/types/new/{OsdkContext2.d.ts → OsdkContext.d.ts} +3 -3
- package/build/types/new/OsdkContext.d.ts.map +1 -0
- package/build/types/new/OsdkProvider.d.ts +9 -0
- package/build/types/new/OsdkProvider.d.ts.map +1 -0
- package/build/types/new/createCompositeExternalStore.d.ts +1 -1
- package/build/types/new/createCompositeExternalStore.d.ts.map +1 -1
- package/build/types/new/makeExternalStore.d.ts +1 -1
- package/build/types/new/makeExternalStore.d.ts.map +1 -1
- package/build/types/new/shapes/derivedLinksStore.d.ts +1 -1
- package/build/types/new/shapes/derivedLinksStore.d.ts.map +1 -1
- package/build/types/new/shapes/types.d.ts +1 -1
- package/build/types/new/shapes/types.d.ts.map +1 -1
- package/build/types/new/useDevToolsClient.d.ts +1 -1
- package/build/types/new/useDevToolsClient.d.ts.map +1 -1
- package/build/types/new/useLinks.d.ts +11 -3
- package/build/types/new/useLinks.d.ts.map +1 -1
- package/build/types/new/useObjectSet.d.ts +3 -1
- package/build/types/new/useObjectSet.d.ts.map +1 -1
- package/build/types/new/useOsdkAction.d.ts +1 -1
- package/build/types/new/useOsdkAction.d.ts.map +1 -1
- package/build/types/new/useOsdkAggregation.d.ts +1 -1
- package/build/types/new/useOsdkAggregation.d.ts.map +1 -1
- package/build/types/new/useOsdkFunction.d.ts +1 -1
- package/build/types/new/useOsdkFunction.d.ts.map +1 -1
- package/build/types/new/useOsdkObjects.d.ts +10 -4
- package/build/types/new/useOsdkObjects.d.ts.map +1 -1
- package/build/types/public/devtools-registry.d.ts +1 -1
- package/build/types/public/devtools-registry.d.ts.map +1 -1
- package/build/types/public/experimental/admin.d.ts +16 -0
- package/build/types/public/experimental/admin.d.ts.map +1 -1
- package/build/types/public/experimental/aip.d.ts +4 -0
- package/build/types/public/experimental/aip.d.ts.map +1 -0
- package/build/types/public/experimental.d.ts +36 -2
- package/build/types/public/experimental.d.ts.map +1 -1
- package/build/types/public/platform-apis.d.ts +11 -0
- package/build/types/public/platform-apis.d.ts.map +1 -0
- package/build/types/public/testing.d.ts +24 -0
- package/build/types/public/testing.d.ts.map +1 -0
- package/build/types/useObservableClient.d.ts +20 -0
- package/build/types/useObservableClient.d.ts.map +1 -0
- package/build/types/useOsdkClient.d.ts +0 -1
- package/build/types/useOsdkClient.d.ts.map +1 -1
- package/docs/actions.md +8 -12
- package/docs/advanced-queries.md +17 -23
- package/docs/cache-management.md +13 -13
- package/docs/getting-started.md +34 -109
- package/docs/platform-apis.md +4 -4
- package/docs/prerequisites.md +5 -5
- package/docs/querying-data.md +14 -23
- package/{build/browser/OsdkContext.js → experimental/aip.d.ts} +2 -12
- package/experimental.d.ts +1 -1
- package/package.json +39 -7
- package/{build/esm/OsdkContext.js → platform-apis.d.ts} +2 -12
- package/testing.d.ts +17 -0
- package/build/browser/OsdkContext.js.map +0 -1
- package/build/browser/OsdkProvider.js.map +0 -1
- package/build/browser/new/OsdkContext2.js.map +0 -1
- package/build/browser/new/OsdkProvider2.js.map +0 -1
- package/build/cjs/chunk-2Y5CIQPC.cjs.map +0 -1
- package/build/cjs/chunk-MERQDEQC.cjs +0 -54
- package/build/cjs/chunk-MERQDEQC.cjs.map +0 -1
- package/build/cjs/useOsdkMetadata-CRTcdg-a.d.cts +0 -16
- package/build/esm/OsdkContext.js.map +0 -1
- package/build/esm/OsdkProvider.js.map +0 -1
- package/build/esm/new/OsdkContext2.js.map +0 -1
- package/build/esm/new/OsdkProvider2.js.map +0 -1
- package/build/types/OsdkContext.d.ts +0 -5
- package/build/types/OsdkContext.d.ts.map +0 -1
- package/build/types/OsdkProvider.d.ts +0 -6
- package/build/types/OsdkProvider.d.ts.map +0 -1
- package/build/types/new/OsdkContext2.d.ts.map +0 -1
- package/build/types/new/OsdkProvider2.d.ts +0 -11
- package/build/types/new/OsdkProvider2.d.ts.map +0 -1
package/AGENTS.md
CHANGED
|
@@ -2,12 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
## Installing
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
`pnpm add @osdk/react@latest`. Must install `@osdk/react` AND `@osdk/client` AND `@osdk/api` together, and the versions must line up tighter than the declared peer ranges. `@osdk/react` imports its observable runtime from `@osdk/client/observable`, which is version-locked across the three packages.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
- **Stable `@osdk/react`** (e.g. `0.14.x`) → latest stable `@osdk/client` and `@osdk/api` (`2.x`).
|
|
10
|
-
- **Prerelease `@osdk/react`** (e.g. `0.10.0-beta.15`) → MUST use prerelease `@osdk/client` and `@osdk/api` from the same line. Stable releases will break.
|
|
7
|
+
- **Stable `@osdk/react`** (e.g. `1.x`) → latest stable `@osdk/client` and `@osdk/api` (`2.x`).
|
|
8
|
+
- **Prerelease `@osdk/react`** → MUST use prerelease `@osdk/client` and `@osdk/api` from the same line. Stable releases will break.
|
|
11
9
|
|
|
12
10
|
To find the exact compatible `@osdk/client` and `@osdk/api` for any installed `@osdk/react`:
|
|
13
11
|
|
|
@@ -16,52 +14,43 @@ To find the exact compatible `@osdk/client` and `@osdk/api` for any installed `@
|
|
|
16
14
|
3. If that entry has an `Updated dependencies` section, install the exact `@osdk/client@X.Y.Z` AND `@osdk/api@X.Y.Z` it lists
|
|
17
15
|
4. If it does NOT, walk backwards to the most recent prior entry that does, and use those versions
|
|
18
16
|
|
|
19
|
-
**Worked example** — installed `@osdk/react@0.10.0-beta.15`:
|
|
20
|
-
|
|
21
|
-
- `0.10.0-beta.15` has no `Updated dependencies` section → walk back
|
|
22
|
-
- `0.10.0-beta.14` lists `@osdk/client@2.8.0-beta.29` and `@osdk/api@2.8.0-beta.29`
|
|
23
|
-
- Run: `pnpm add @osdk/client@2.8.0-beta.29 @osdk/api@2.8.0-beta.29`
|
|
24
|
-
|
|
25
17
|
**Optional peers** (install only if you import from the matching surface):
|
|
26
18
|
|
|
27
|
-
- `@osdk/foundry.admin` + `@osdk/foundry.core`: required ONLY for any hook from `@osdk/react/
|
|
19
|
+
- `@osdk/foundry.admin` + `@osdk/foundry.core`: required ONLY for any hook from `@osdk/react/platform-apis`. Otherwise omit.
|
|
28
20
|
|
|
29
21
|
## Install-time errors
|
|
30
22
|
|
|
31
|
-
| Error
|
|
32
|
-
|
|
|
33
|
-
| `"<name>" is not exported by @osdk/client/.../unstable-do-not-use.js
|
|
34
|
-
| `Rollup failed to resolve import "@osdk/foundry.admin"` (or `@osdk/foundry.core`)
|
|
35
|
-
| pnpm/npm peer warning about `@osdk/client` or `@osdk/api` range
|
|
23
|
+
| Error | Cause | Fix |
|
|
24
|
+
| ------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
25
|
+
| `"<name>" is not exported by @osdk/client/.../observable.js` (or `@osdk/client/.../unstable-do-not-use.js`, or `@osdk/api/...`) | `@osdk/client` or `@osdk/api` is on a different release line than the one `@osdk/react` was built against — usually a prerelease `@osdk/react` paired with stable peers (or vice versa) | Do NOT delete the import or downgrade `@osdk/react` silently. Follow the CHANGELOG recipe in `## Installing` to find the exact `@osdk/client` and `@osdk/api` versions, then `pnpm add @osdk/client@<version> @osdk/api@<version>`. |
|
|
26
|
+
| `Rollup failed to resolve import "@osdk/foundry.admin"` (or `@osdk/foundry.core`) | Imported from `@osdk/react/platform-apis` without installing the optional peers | Install `@osdk/foundry.admin` + `@osdk/foundry.core`, OR stop importing from `/platform-apis`. |
|
|
27
|
+
| pnpm/npm peer warning about `@osdk/client` or `@osdk/api` range | Declared peer ranges are deliberately broad; prerelease coupling is tighter than the ranges express | Follow the CHANGELOG recipe; pin to the exact `@osdk/client` and `@osdk/api` versions. |
|
|
36
28
|
|
|
37
29
|
## Rules
|
|
38
30
|
|
|
39
|
-
1. **
|
|
40
|
-
2. **
|
|
41
|
-
3. **
|
|
42
|
-
4.
|
|
43
|
-
5. **`useOsdkObject` `enabled` is positional**, not in an options object: `useOsdkObject(Type, id, false)`.
|
|
31
|
+
1. **Wrap your app in `OsdkProvider`** at the root. All hooks require it.
|
|
32
|
+
2. **Never conditionally call hooks.** Use the `enabled` option instead.
|
|
33
|
+
3. **Keep rendering during loading.** No early returns like `if (isLoading) return <Spinner />`. Show loading indicators alongside existing data to prevent UI flashing. Exception: `if (!data && isLoading)` is acceptable for initial load.
|
|
34
|
+
4. **`useOsdkObject` `enabled` is positional**, not in an options object: `useOsdkObject(Type, id, false)`.
|
|
44
35
|
|
|
45
36
|
## Exports
|
|
46
37
|
|
|
47
|
-
**
|
|
38
|
+
**Main entry** (`@osdk/react`): `OsdkProvider`, `useOsdkObjects`, `useOsdkObject`, `useOsdkAction`, `useLinks`, `useObjectSet`, `useOsdkAggregation`, `useOsdkFunction`, `useOsdkFunctions`, `useStableObjectSet`, `useRegisterUserAgent`, `useDebouncedCallback`, `useOsdkClient`, `useOsdkMetadata`, plus the devtools registry re-exports (`registerDevTools`, `getRegisteredDevTools`).
|
|
39
|
+
|
|
40
|
+
**Platform APIs** (`@osdk/react/platform-apis`): `useCurrentFoundryUser`, `useFoundryUser`, `useFoundryUsersList`, `useMarkings`, `useMarkingCategories`, `useUserViewMarkings`, `useCbacBanner`, `useCbacMarkingRestrictions` — requires `@osdk/foundry.admin` + `@osdk/foundry.core` to be installed.
|
|
48
41
|
|
|
49
|
-
**
|
|
42
|
+
**DevTools** (`@osdk/react/devtools-registry`): `registerDevTools`, `getRegisteredDevTools`, `DevToolsRegistry` (also re-exported from main).
|
|
50
43
|
|
|
51
44
|
## Hook Options
|
|
52
45
|
|
|
53
|
-
- `
|
|
46
|
+
- `OsdkProvider` - Wrap your app at the root
|
|
54
47
|
- `useOsdkObjects` - Query lists of objects
|
|
55
48
|
- `useOsdkObject` - Query single object by type+key or instance
|
|
56
49
|
- `useOsdkAction` - Execute and validate actions
|
|
57
50
|
- `useLinks` - Navigate object relationships
|
|
58
51
|
- `useObjectSet` - Advanced set operations (union, intersect, subtract, pivot)
|
|
59
52
|
- `useOsdkAggregation` - Server-side aggregations with groupBy/select
|
|
60
|
-
- `
|
|
61
|
-
|
|
62
|
-
**Experimental Admin** (`@osdk/react/experimental/admin`):
|
|
63
|
-
|
|
64
|
-
- `useCurrentFoundryUser`, `useFoundryUser`, `useFoundryUsersList` - Platform APIs (requires `@osdk/foundry.admin`)
|
|
53
|
+
- `useOsdkFunction` / `useOsdkFunctions` - Call ontology functions
|
|
65
54
|
|
|
66
55
|
## Correct Patterns
|
|
67
56
|
|
|
@@ -100,11 +89,6 @@ if (isLoading) return <Spinner />;
|
|
|
100
89
|
// CORRECT: render together
|
|
101
90
|
<div>{isLoading && <Spinner />}{data?.map(...)}</div>
|
|
102
91
|
|
|
103
|
-
// WRONG: import from main entry
|
|
104
|
-
import { useOsdkObjects } from "@osdk/react";
|
|
105
|
-
// CORRECT
|
|
106
|
-
import { useOsdkObjects } from "@osdk/react/experimental";
|
|
107
|
-
|
|
108
92
|
// WRONG: useOsdkObject enabled in options
|
|
109
93
|
useOsdkObject(Employee, id, { enabled: false });
|
|
110
94
|
// CORRECT: positional
|
package/CHANGELOG.md
CHANGED
|
@@ -1,20 +1,21 @@
|
|
|
1
1
|
# @osdkkit/react
|
|
2
2
|
|
|
3
|
-
## 0.17.0
|
|
3
|
+
## 0.17.0
|
|
4
4
|
|
|
5
5
|
### Minor Changes
|
|
6
6
|
|
|
7
|
+
- f747fa3: Add `@osdk/aip-core` — the AIP SDK's chat completion primitives, backed by the Foundry Language Model Service's OpenAI-compatible proxy. Construct a model via `foundryModel({ client, model })` and call `generateText` for non-streaming completions or `streamText` for streaming. `LmsChatTransport` plugs into UI hooks; `useChat` is exposed from `@osdk/react/experimental/aip` and returns `messages`, `status`, `sendMessage`, `regenerate`, `stop`, `clearError`, and accepts a `transport` override. v0 is text-only and single-step — tool round-trips, multi-step loops, image/file content, Zod tool schemas, and stream resume are deferred.
|
|
8
|
+
- d892397: expose `$includeAllBaseObjectProperties` on `useLinks` and on the underlying `ObservableClient.observeLinks`. When set against a link whose target is an interface, the server returns the underlying concrete object's full property set so `obj.$as(ConcreteType)` yields a fully-populated concrete object. The flag is dropped at fetch time when the link target is an object type and does not narrow the returned `Osdk.Instance` type.
|
|
7
9
|
- c5a6047: expose `$includeAllBaseObjectProperties` on `useOsdkObject` and on the underlying `ObservableClient.observeObject`. When set against an interface query, the server returns the underlying concrete object's full property set so `obj.$as(ConcreteType)` yields a fully-populated concrete object. The flag is dropped for non-interface queries and does not narrow the returned `Osdk.Instance` type.
|
|
8
10
|
- 45be476: expose `$includeAllBaseObjectProperties` on `useOsdkObjects` and on the underlying `ObservableClient.observeList`. When set against an interface query, the server returns the underlying concrete object's full property set so `obj.$as(ConcreteType)` yields a fully-populated concrete object. The flag is dropped for non-interface queries and does not narrow the returned `Osdk.Instance` type.
|
|
11
|
+
- b355bc3: Add CONTRIBUTING.md for @osdk/react and @osdk/react-components
|
|
12
|
+
- 20e9678: Wrap `@example` JSDoc blocks in fenced ts/tsx code blocks so VS Code's Markdown renderer preserves whitespace and applies syntax highlighting.
|
|
9
13
|
|
|
10
14
|
### Patch Changes
|
|
11
15
|
|
|
12
|
-
-
|
|
13
|
-
- Updated dependencies [
|
|
14
|
-
-
|
|
15
|
-
- Updated dependencies [45be476]
|
|
16
|
-
- @osdk/client@2.14.0-main-5dc557e9e321d23e8e150e8015c41ebe3b6f387c
|
|
17
|
-
- @osdk/api@2.14.0-main-5dc557e9e321d23e8e150e8015c41ebe3b6f387c
|
|
16
|
+
- Updated dependencies [86cc68c]
|
|
17
|
+
- Updated dependencies [f747fa3]
|
|
18
|
+
- @osdk/aip-core@0.2.0
|
|
18
19
|
|
|
19
20
|
## 0.16.0
|
|
20
21
|
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2026 Palantir Technologies, Inc. All rights reserved.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Tiny pub-sub store backing `useChat`. Throttles subscriber notifications so
|
|
19
|
+
* fast token-delta streams don't trigger one render per token.
|
|
20
|
+
*/
|
|
21
|
+
export function createChatStore(options) {
|
|
22
|
+
let state = {
|
|
23
|
+
messages: options.initialMessages ?? [],
|
|
24
|
+
status: "ready",
|
|
25
|
+
error: undefined
|
|
26
|
+
};
|
|
27
|
+
const subscribers = new Set();
|
|
28
|
+
const throttleMs = options.throttleMs ?? 0;
|
|
29
|
+
let pendingNotify;
|
|
30
|
+
const notifyNow = () => {
|
|
31
|
+
if (pendingNotify != null) {
|
|
32
|
+
clearTimeout(pendingNotify);
|
|
33
|
+
pendingNotify = undefined;
|
|
34
|
+
}
|
|
35
|
+
for (const s of subscribers) {
|
|
36
|
+
s();
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
const notifyThrottled = () => {
|
|
40
|
+
if (throttleMs <= 0) {
|
|
41
|
+
notifyNow();
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
if (pendingNotify != null) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
pendingNotify = setTimeout(notifyNow, throttleMs);
|
|
48
|
+
};
|
|
49
|
+
return {
|
|
50
|
+
getSnapshot: () => state,
|
|
51
|
+
subscribe: notify => {
|
|
52
|
+
subscribers.add(notify);
|
|
53
|
+
return () => {
|
|
54
|
+
subscribers.delete(notify);
|
|
55
|
+
};
|
|
56
|
+
},
|
|
57
|
+
setState: next => {
|
|
58
|
+
state = typeof next === "function" ? next(state) : next;
|
|
59
|
+
notifyNow();
|
|
60
|
+
},
|
|
61
|
+
setStateThrottled: next => {
|
|
62
|
+
state = typeof next === "function" ? next(state) : next;
|
|
63
|
+
notifyThrottled();
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=chatStore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chatStore.js","names":["createChatStore","options","state","messages","initialMessages","status","error","undefined","subscribers","Set","throttleMs","pendingNotify","notifyNow","clearTimeout","s","notifyThrottled","setTimeout","getSnapshot","subscribe","notify","add","delete","setState","next","setStateThrottled"],"sources":["chatStore.ts"],"sourcesContent":["/*\n * Copyright 2026 Palantir Technologies, Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { UIMessage } from \"@osdk/aip-core\";\n\nexport type ChatStatus = \"ready\" | \"submitted\" | \"streaming\" | \"error\";\n\nexport interface ChatState {\n messages: ReadonlyArray<UIMessage>;\n status: ChatStatus;\n error: Error | undefined;\n}\n\nexport interface ChatStore {\n getSnapshot: () => ChatState;\n /** Subscribe to state changes. Returns the unsubscribe function. */\n subscribe: (notify: () => void) => () => void;\n /** Replace state and notify subscribers synchronously. */\n setState: (\n next: ChatState | ((prev: ChatState) => ChatState),\n ) => void;\n /**\n * Replace state and coalesce subscriber notifications across rapid calls.\n * Notifications fire `throttleMs` after the first change in a quiet window.\n * Use for high-frequency updates (e.g. token streaming) where one render per\n * change is wasteful.\n */\n setStateThrottled: (\n next: ChatState | ((prev: ChatState) => ChatState),\n ) => void;\n}\n\nexport interface CreateChatStoreOptions {\n initialMessages?: ReadonlyArray<UIMessage>;\n /** Min ms between subscriber notifications. 0 = synchronous. Defaults to 0. */\n throttleMs?: number;\n}\n\n/**\n * Tiny pub-sub store backing `useChat`. Throttles subscriber notifications so\n * fast token-delta streams don't trigger one render per token.\n */\nexport function createChatStore(options: CreateChatStoreOptions): ChatStore {\n let state: ChatState = {\n messages: options.initialMessages ?? [],\n status: \"ready\",\n error: undefined,\n };\n\n const subscribers = new Set<() => void>();\n const throttleMs = options.throttleMs ?? 0;\n let pendingNotify: ReturnType<typeof setTimeout> | undefined;\n\n const notifyNow = (): void => {\n if (pendingNotify != null) {\n clearTimeout(pendingNotify);\n pendingNotify = undefined;\n }\n for (const s of subscribers) {\n s();\n }\n };\n\n const notifyThrottled = (): void => {\n if (throttleMs <= 0) {\n notifyNow();\n return;\n }\n if (pendingNotify != null) {\n return;\n }\n pendingNotify = setTimeout(notifyNow, throttleMs);\n };\n\n return {\n getSnapshot: () => state,\n subscribe: (notify) => {\n subscribers.add(notify);\n return () => {\n subscribers.delete(notify);\n };\n },\n setState: (next) => {\n state = typeof next === \"function\" ? next(state) : next;\n notifyNow();\n },\n setStateThrottled: (next) => {\n state = typeof next === \"function\" ? next(state) : next;\n notifyThrottled();\n },\n };\n}\n"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAqCA;AACA;AACA;AACA;AACA,OAAO,SAASA,eAAeA,CAACC,OAA+B,EAAa;EAC1E,IAAIC,KAAgB,GAAG;IACrBC,QAAQ,EAAEF,OAAO,CAACG,eAAe,IAAI,EAAE;IACvCC,MAAM,EAAE,OAAO;IACfC,KAAK,EAAEC;EACT,CAAC;EAED,MAAMC,WAAW,GAAG,IAAIC,GAAG,CAAa,CAAC;EACzC,MAAMC,UAAU,GAAGT,OAAO,CAACS,UAAU,IAAI,CAAC;EAC1C,IAAIC,aAAwD;EAE5D,MAAMC,SAAS,GAAGA,CAAA,KAAY;IAC5B,IAAID,aAAa,IAAI,IAAI,EAAE;MACzBE,YAAY,CAACF,aAAa,CAAC;MAC3BA,aAAa,GAAGJ,SAAS;IAC3B;IACA,KAAK,MAAMO,CAAC,IAAIN,WAAW,EAAE;MAC3BM,CAAC,CAAC,CAAC;IACL;EACF,CAAC;EAED,MAAMC,eAAe,GAAGA,CAAA,KAAY;IAClC,IAAIL,UAAU,IAAI,CAAC,EAAE;MACnBE,SAAS,CAAC,CAAC;MACX;IACF;IACA,IAAID,aAAa,IAAI,IAAI,EAAE;MACzB;IACF;IACAA,aAAa,GAAGK,UAAU,CAACJ,SAAS,EAAEF,UAAU,CAAC;EACnD,CAAC;EAED,OAAO;IACLO,WAAW,EAAEA,CAAA,KAAMf,KAAK;IACxBgB,SAAS,EAAGC,MAAM,IAAK;MACrBX,WAAW,CAACY,GAAG,CAACD,MAAM,CAAC;MACvB,OAAO,MAAM;QACXX,WAAW,CAACa,MAAM,CAACF,MAAM,CAAC;MAC5B,CAAC;IACH,CAAC;IACDG,QAAQ,EAAGC,IAAI,IAAK;MAClBrB,KAAK,GAAG,OAAOqB,IAAI,KAAK,UAAU,GAAGA,IAAI,CAACrB,KAAK,CAAC,GAAGqB,IAAI;MACvDX,SAAS,CAAC,CAAC;IACb,CAAC;IACDY,iBAAiB,EAAGD,IAAI,IAAK;MAC3BrB,KAAK,GAAG,OAAOqB,IAAI,KAAK,UAAU,GAAGA,IAAI,CAACrB,KAAK,CAAC,GAAGqB,IAAI;MACvDR,eAAe,CAAC,CAAC;IACnB;EACF,CAAC;AACH","ignoreList":[]}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2026 Palantir Technologies, Inc. All rights reserved.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { generateMessageId } from "@osdk/aip-core";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Mutable orchestration handle threaded through the streaming functions.
|
|
21
|
+
* Holds everything they need to read snapshots, mutate state, and check
|
|
22
|
+
* whether their stream is still the active one.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
export async function runChatStream(ctx, transport, chatId, seed, trigger) {
|
|
26
|
+
ctx.abortRef.current?.abort();
|
|
27
|
+
const ctrl = new AbortController();
|
|
28
|
+
ctx.abortRef.current = ctrl;
|
|
29
|
+
ctx.stoppedRef.current = false;
|
|
30
|
+
const assistantId = generateMessageId();
|
|
31
|
+
try {
|
|
32
|
+
const stream = await transport.sendMessages({
|
|
33
|
+
trigger,
|
|
34
|
+
chatId,
|
|
35
|
+
messageId: assistantId,
|
|
36
|
+
messages: seed.slice(),
|
|
37
|
+
abortSignal: ctrl.signal
|
|
38
|
+
});
|
|
39
|
+
await drainStream(ctx, stream, assistantId, ctrl);
|
|
40
|
+
} catch (err) {
|
|
41
|
+
handleStreamError(ctx, err, ctrl);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
export async function drainStream(ctx, stream, assistantMessageId, capturedCtrl) {
|
|
45
|
+
const {
|
|
46
|
+
store
|
|
47
|
+
} = ctx;
|
|
48
|
+
const reader = stream.getReader();
|
|
49
|
+
let textBuf = "";
|
|
50
|
+
const isStale = () => ctx.abortRef.current != null && ctx.abortRef.current !== capturedCtrl;
|
|
51
|
+
|
|
52
|
+
// Caller dropped our assistant message via `setMessages` mid-stream.
|
|
53
|
+
// Treat as "the consumer no longer wants this stream" — quietly stop.
|
|
54
|
+
const isOrphaned = () => {
|
|
55
|
+
const messages = store.getSnapshot().messages;
|
|
56
|
+
return textBuf.length > 0 && !messages.some(m => m.id === assistantMessageId);
|
|
57
|
+
};
|
|
58
|
+
try {
|
|
59
|
+
while (true) {
|
|
60
|
+
const {
|
|
61
|
+
done,
|
|
62
|
+
value
|
|
63
|
+
} = await reader.read();
|
|
64
|
+
if (done) {
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
if (isStale()) {
|
|
68
|
+
await reader.cancel();
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
if (isOrphaned()) {
|
|
72
|
+
await reader.cancel();
|
|
73
|
+
store.setState(prev => ({
|
|
74
|
+
...prev,
|
|
75
|
+
status: "ready"
|
|
76
|
+
}));
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
if (value.type === "text-delta") {
|
|
80
|
+
textBuf += value.delta;
|
|
81
|
+
upsertAssistantText(store, assistantMessageId, textBuf);
|
|
82
|
+
} else if (value.type === "error") {
|
|
83
|
+
if (ctx.stoppedRef.current || capturedCtrl.signal.aborted) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
await reader.cancel();
|
|
87
|
+
throw new Error(value.errorText);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (isStale()) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
store.setState(prev => ({
|
|
94
|
+
...prev,
|
|
95
|
+
status: "ready"
|
|
96
|
+
}));
|
|
97
|
+
const finalSnap = store.getSnapshot();
|
|
98
|
+
const finalMessage = finalSnap.messages.find(m => m.id === assistantMessageId);
|
|
99
|
+
if (finalMessage != null && ctx.onFinish != null) {
|
|
100
|
+
ctx.onFinish({
|
|
101
|
+
message: finalMessage,
|
|
102
|
+
messages: finalSnap.messages
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
} catch (err) {
|
|
106
|
+
handleStreamError(ctx, err, capturedCtrl);
|
|
107
|
+
} finally {
|
|
108
|
+
reader.releaseLock();
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
function upsertAssistantText(store, assistantMessageId, text) {
|
|
112
|
+
store.setStateThrottled(prev => {
|
|
113
|
+
const exists = prev.messages.some(m => m.id === assistantMessageId);
|
|
114
|
+
const messages = exists ? prev.messages.map(m => m.id === assistantMessageId ? {
|
|
115
|
+
...m,
|
|
116
|
+
parts: [{
|
|
117
|
+
type: "text",
|
|
118
|
+
text
|
|
119
|
+
}]
|
|
120
|
+
} : m) : [...prev.messages, {
|
|
121
|
+
id: assistantMessageId,
|
|
122
|
+
role: "assistant",
|
|
123
|
+
parts: [{
|
|
124
|
+
type: "text",
|
|
125
|
+
text
|
|
126
|
+
}]
|
|
127
|
+
}];
|
|
128
|
+
return {
|
|
129
|
+
...prev,
|
|
130
|
+
status: "streaming",
|
|
131
|
+
messages
|
|
132
|
+
};
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
function handleStreamError(ctx, err, capturedCtrl) {
|
|
136
|
+
if (ctx.abortRef.current != null && ctx.abortRef.current !== capturedCtrl) {
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
140
|
+
if (ctx.stoppedRef.current || error.name === "AbortError" || capturedCtrl.signal.aborted) {
|
|
141
|
+
ctx.store.setState(prev => ({
|
|
142
|
+
...prev,
|
|
143
|
+
status: "ready",
|
|
144
|
+
error: undefined
|
|
145
|
+
}));
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
ctx.store.setState(prev => ({
|
|
149
|
+
...prev,
|
|
150
|
+
status: "error",
|
|
151
|
+
error
|
|
152
|
+
}));
|
|
153
|
+
ctx.onError?.(error);
|
|
154
|
+
}
|
|
155
|
+
//# sourceMappingURL=chatStream.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chatStream.js","names":["generateMessageId","runChatStream","ctx","transport","chatId","seed","trigger","abortRef","current","abort","ctrl","AbortController","stoppedRef","assistantId","stream","sendMessages","messageId","messages","slice","abortSignal","signal","drainStream","err","handleStreamError","assistantMessageId","capturedCtrl","store","reader","getReader","textBuf","isStale","isOrphaned","getSnapshot","length","some","m","id","done","value","read","cancel","setState","prev","status","type","delta","upsertAssistantText","aborted","Error","errorText","finalSnap","finalMessage","find","onFinish","message","releaseLock","text","setStateThrottled","exists","map","parts","role","error","String","name","undefined","onError"],"sources":["chatStream.ts"],"sourcesContent":["/*\n * Copyright 2026 Palantir Technologies, Inc. All rights reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n type ChatTransport,\n generateMessageId,\n type UIMessage,\n type UIMessageChunk,\n} from \"@osdk/aip-core\";\nimport type React from \"react\";\nimport type { ChatStore } from \"./chatStore.js\";\n\n/**\n * Mutable orchestration handle threaded through the streaming functions.\n * Holds everything they need to read snapshots, mutate state, and check\n * whether their stream is still the active one.\n */\nexport interface StreamContext {\n store: ChatStore;\n abortRef: React.MutableRefObject<AbortController | undefined>;\n stoppedRef: React.MutableRefObject<boolean>;\n onFinish:\n | ((event: {\n message: UIMessage;\n messages: ReadonlyArray<UIMessage>;\n }) => void)\n | undefined;\n onError: ((error: Error) => void) | undefined;\n}\n\nexport async function runChatStream(\n ctx: StreamContext,\n transport: ChatTransport<UIMessage>,\n chatId: string,\n seed: ReadonlyArray<UIMessage>,\n trigger: \"submit-message\" | \"regenerate-message\",\n): Promise<void> {\n ctx.abortRef.current?.abort();\n const ctrl = new AbortController();\n ctx.abortRef.current = ctrl;\n ctx.stoppedRef.current = false;\n\n const assistantId = generateMessageId();\n try {\n const stream = await transport.sendMessages({\n trigger,\n chatId,\n messageId: assistantId,\n messages: seed.slice(),\n abortSignal: ctrl.signal,\n });\n await drainStream(ctx, stream, assistantId, ctrl);\n } catch (err) {\n handleStreamError(ctx, err, ctrl);\n }\n}\n\nexport async function drainStream(\n ctx: StreamContext,\n stream: ReadableStream<UIMessageChunk>,\n assistantMessageId: string,\n capturedCtrl: AbortController,\n): Promise<void> {\n const { store } = ctx;\n const reader = stream.getReader();\n let textBuf = \"\";\n\n const isStale = (): boolean =>\n ctx.abortRef.current != null && ctx.abortRef.current !== capturedCtrl;\n\n // Caller dropped our assistant message via `setMessages` mid-stream.\n // Treat as \"the consumer no longer wants this stream\" — quietly stop.\n const isOrphaned = (): boolean => {\n const messages = store.getSnapshot().messages;\n return textBuf.length > 0\n && !messages.some((m) => m.id === assistantMessageId);\n };\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) {\n break;\n }\n if (isStale()) {\n await reader.cancel();\n return;\n }\n if (isOrphaned()) {\n await reader.cancel();\n store.setState((prev) => ({ ...prev, status: \"ready\" }));\n return;\n }\n if (value.type === \"text-delta\") {\n textBuf += value.delta;\n upsertAssistantText(store, assistantMessageId, textBuf);\n } else if (value.type === \"error\") {\n if (ctx.stoppedRef.current || capturedCtrl.signal.aborted) {\n return;\n }\n await reader.cancel();\n throw new Error(value.errorText);\n }\n }\n if (isStale()) {\n return;\n }\n store.setState((prev) => ({ ...prev, status: \"ready\" }));\n const finalSnap = store.getSnapshot();\n const finalMessage = finalSnap.messages.find(\n (m) => m.id === assistantMessageId,\n );\n if (finalMessage != null && ctx.onFinish != null) {\n ctx.onFinish({ message: finalMessage, messages: finalSnap.messages });\n }\n } catch (err) {\n handleStreamError(ctx, err, capturedCtrl);\n } finally {\n reader.releaseLock();\n }\n}\n\nfunction upsertAssistantText(\n store: ChatStore,\n assistantMessageId: string,\n text: string,\n): void {\n store.setStateThrottled((prev) => {\n const exists = prev.messages.some((m) => m.id === assistantMessageId);\n const messages = exists\n ? prev.messages.map((m) =>\n m.id === assistantMessageId\n ? { ...m, parts: [{ type: \"text\" as const, text }] }\n : m\n )\n : [\n ...prev.messages,\n {\n id: assistantMessageId,\n role: \"assistant\" as const,\n parts: [{ type: \"text\" as const, text }],\n },\n ];\n return { ...prev, status: \"streaming\", messages };\n });\n}\n\nfunction handleStreamError(\n ctx: StreamContext,\n err: unknown,\n capturedCtrl: AbortController,\n): void {\n if (ctx.abortRef.current != null && ctx.abortRef.current !== capturedCtrl) {\n return;\n }\n const error = err instanceof Error ? err : new Error(String(err));\n if (\n ctx.stoppedRef.current\n || error.name === \"AbortError\"\n || capturedCtrl.signal.aborted\n ) {\n ctx.store.setState((prev) => ({\n ...prev,\n status: \"ready\",\n error: undefined,\n }));\n return;\n }\n ctx.store.setState((prev) => ({ ...prev, status: \"error\", error }));\n ctx.onError?.(error);\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2026 Palantir Technologies, Inc. All rights reserved.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { generateMessageId, LmsChatTransport } from "@osdk/aip-core";
|
|
18
|
+
import React from "react";
|
|
19
|
+
import { createChatStore } from "./chatStore.js";
|
|
20
|
+
import { drainStream, runChatStream } from "./chatStream.js";
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Options for {@link useChat}.
|
|
24
|
+
*
|
|
25
|
+
* v0 covers text-only chat. Tools, multi-step agent loops, and stream
|
|
26
|
+
* resume are not supported.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
/** Return value of {@link useChat}. */
|
|
30
|
+
|
|
31
|
+
/** Input shape accepted by `sendMessage`. */
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* React hook for streaming chat completions through `@osdk/aip-core`'s
|
|
35
|
+
* `streamText`.
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```tsx
|
|
39
|
+
* const { messages, status, sendMessage, stop, error } = useChat({
|
|
40
|
+
* model: foundryModel({ client, model: "gpt-4o" }),
|
|
41
|
+
* system: "You are a concise assistant.",
|
|
42
|
+
* });
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export function useChat(options) {
|
|
46
|
+
const {
|
|
47
|
+
onFinish,
|
|
48
|
+
onError
|
|
49
|
+
} = options;
|
|
50
|
+
const id = React.useMemo(() => options.id ?? generateMessageId(), [options.id]);
|
|
51
|
+
|
|
52
|
+
// JSON-stringify keys keep the memo stable when callers pass inline objects.
|
|
53
|
+
const headersKey = JSON.stringify(options.headers ?? null);
|
|
54
|
+
const stopSequencesKey = JSON.stringify(options.stopSequences ?? null);
|
|
55
|
+
const transport = React.useMemo(() => {
|
|
56
|
+
if (options.transport != null) {
|
|
57
|
+
return options.transport;
|
|
58
|
+
}
|
|
59
|
+
if (options.model == null) {
|
|
60
|
+
throw new Error("useChat: `model` is required when no `transport` is provided.");
|
|
61
|
+
}
|
|
62
|
+
const built = {
|
|
63
|
+
model: options.model,
|
|
64
|
+
system: options.system,
|
|
65
|
+
temperature: options.temperature,
|
|
66
|
+
maxOutputTokens: options.maxOutputTokens,
|
|
67
|
+
topP: options.topP,
|
|
68
|
+
presencePenalty: options.presencePenalty,
|
|
69
|
+
frequencyPenalty: options.frequencyPenalty,
|
|
70
|
+
stopSequences: options.stopSequences,
|
|
71
|
+
seed: options.seed,
|
|
72
|
+
headers: options.headers
|
|
73
|
+
};
|
|
74
|
+
return new LmsChatTransport(built);
|
|
75
|
+
},
|
|
76
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
77
|
+
[options.transport, options.model, options.system, options.temperature, options.maxOutputTokens, options.topP, options.presencePenalty, options.frequencyPenalty, options.seed, headersKey, stopSequencesKey]);
|
|
78
|
+
const store = React.useMemo(() => createChatStore({
|
|
79
|
+
initialMessages: options.messages,
|
|
80
|
+
throttleMs: options.experimentalThrottle ?? 50
|
|
81
|
+
}),
|
|
82
|
+
// Recreating the store mid-session would drop chat state, so it's keyed
|
|
83
|
+
// only by `id`. Use `setMessages` to mutate messages at runtime.
|
|
84
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
85
|
+
[id]);
|
|
86
|
+
const state = React.useSyncExternalStore(store.subscribe, store.getSnapshot, store.getSnapshot);
|
|
87
|
+
const abortRef = React.useRef(undefined);
|
|
88
|
+
const stoppedRef = React.useRef(false);
|
|
89
|
+
const ctxRef = React.useRef({
|
|
90
|
+
store,
|
|
91
|
+
abortRef,
|
|
92
|
+
stoppedRef,
|
|
93
|
+
onFinish,
|
|
94
|
+
onError
|
|
95
|
+
});
|
|
96
|
+
ctxRef.current = {
|
|
97
|
+
store,
|
|
98
|
+
abortRef,
|
|
99
|
+
stoppedRef,
|
|
100
|
+
onFinish,
|
|
101
|
+
onError
|
|
102
|
+
};
|
|
103
|
+
const runStream = React.useCallback((seed, trigger) => runChatStream(ctxRef.current, transport, id, seed, trigger), [transport, id]);
|
|
104
|
+
const sendMessage = React.useCallback(async input => {
|
|
105
|
+
const userMsg = normalizeUserMessage(input);
|
|
106
|
+
const seeded = [...store.getSnapshot().messages, userMsg];
|
|
107
|
+
store.setState({
|
|
108
|
+
messages: seeded,
|
|
109
|
+
status: "submitted",
|
|
110
|
+
error: undefined
|
|
111
|
+
});
|
|
112
|
+
await runStream(seeded, "submit-message");
|
|
113
|
+
}, [store, runStream]);
|
|
114
|
+
const regenerate = React.useCallback(async regenerateOpts => {
|
|
115
|
+
const messages = store.getSnapshot().messages;
|
|
116
|
+
const cutoff = resolveRegenerateCutoff(messages, regenerateOpts?.messageId);
|
|
117
|
+
if (cutoff.kind === "noop") {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
if (cutoff.kind === "error") {
|
|
121
|
+
store.setState(prev => ({
|
|
122
|
+
...prev,
|
|
123
|
+
status: "error",
|
|
124
|
+
error: cutoff.error
|
|
125
|
+
}));
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
const truncated = messages.slice(0, cutoff.index);
|
|
129
|
+
store.setState({
|
|
130
|
+
messages: truncated,
|
|
131
|
+
status: "submitted",
|
|
132
|
+
error: undefined
|
|
133
|
+
});
|
|
134
|
+
await runStream(truncated, "regenerate-message");
|
|
135
|
+
}, [store, runStream]);
|
|
136
|
+
const stop = React.useCallback(() => {
|
|
137
|
+
stoppedRef.current = true;
|
|
138
|
+
abortRef.current?.abort();
|
|
139
|
+
abortRef.current = undefined;
|
|
140
|
+
}, []);
|
|
141
|
+
const resumeStream = React.useCallback(async () => {
|
|
142
|
+
const stream = await transport.reconnectToStream({
|
|
143
|
+
chatId: id
|
|
144
|
+
});
|
|
145
|
+
if (stream == null) {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
abortRef.current?.abort();
|
|
149
|
+
const ctrl = new AbortController();
|
|
150
|
+
abortRef.current = ctrl;
|
|
151
|
+
const assistantId = generateMessageId();
|
|
152
|
+
await drainStream(ctxRef.current, stream, assistantId, ctrl);
|
|
153
|
+
}, [transport, id]);
|
|
154
|
+
const clearError = React.useCallback(() => {
|
|
155
|
+
// Resetting from streaming/submitted would race the in-flight stream, so
|
|
156
|
+
// only reset when status === "error".
|
|
157
|
+
store.setState(prev => prev.status === "error" ? {
|
|
158
|
+
...prev,
|
|
159
|
+
status: "ready",
|
|
160
|
+
error: undefined
|
|
161
|
+
} : prev);
|
|
162
|
+
}, [store]);
|
|
163
|
+
const setMessages = React.useCallback(next => {
|
|
164
|
+
store.setState(prev => {
|
|
165
|
+
if (prev.status === "streaming" || prev.status === "submitted") {
|
|
166
|
+
return prev;
|
|
167
|
+
}
|
|
168
|
+
return {
|
|
169
|
+
...prev,
|
|
170
|
+
messages: typeof next === "function" ? next(prev.messages) : next
|
|
171
|
+
};
|
|
172
|
+
});
|
|
173
|
+
}, [store]);
|
|
174
|
+
return React.useMemo(() => ({
|
|
175
|
+
id,
|
|
176
|
+
messages: state.messages,
|
|
177
|
+
setMessages,
|
|
178
|
+
status: state.status,
|
|
179
|
+
error: state.error,
|
|
180
|
+
sendMessage,
|
|
181
|
+
regenerate,
|
|
182
|
+
stop,
|
|
183
|
+
resumeStream,
|
|
184
|
+
clearError
|
|
185
|
+
}), [id, state.messages, state.status, state.error, setMessages, sendMessage, regenerate, stop, resumeStream, clearError]);
|
|
186
|
+
}
|
|
187
|
+
function resolveRegenerateCutoff(messages, messageId) {
|
|
188
|
+
if (messageId != null) {
|
|
189
|
+
const index = messages.findIndex(m => m.id === messageId);
|
|
190
|
+
if (index < 0) {
|
|
191
|
+
return {
|
|
192
|
+
kind: "noop"
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
const target = messages[index];
|
|
196
|
+
if (target == null || target.role !== "assistant") {
|
|
197
|
+
return {
|
|
198
|
+
kind: "error",
|
|
199
|
+
error: new Error(`useChat.regenerate: messageId "${messageId}" is ` + `not an assistant message; only assistant messages can be regenerated.`)
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
return {
|
|
203
|
+
kind: "ok",
|
|
204
|
+
index
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
const lastAssistant = findLastAssistantIndex(messages);
|
|
208
|
+
if (lastAssistant < 0) {
|
|
209
|
+
return {
|
|
210
|
+
kind: "noop"
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
return {
|
|
214
|
+
kind: "ok",
|
|
215
|
+
index: lastAssistant
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
function normalizeUserMessage(input) {
|
|
219
|
+
if ("text" in input) {
|
|
220
|
+
return {
|
|
221
|
+
id: generateMessageId(),
|
|
222
|
+
role: "user",
|
|
223
|
+
parts: [{
|
|
224
|
+
type: "text",
|
|
225
|
+
text: input.text
|
|
226
|
+
}]
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
return {
|
|
230
|
+
id: generateMessageId(),
|
|
231
|
+
role: input.role,
|
|
232
|
+
parts: input.parts
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
function findLastAssistantIndex(arr) {
|
|
236
|
+
for (let i = arr.length - 1; i >= 0; i--) {
|
|
237
|
+
if (arr[i]?.role === "assistant") {
|
|
238
|
+
return i;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
return -1;
|
|
242
|
+
}
|
|
243
|
+
//# sourceMappingURL=useChat.js.map
|