@letta-ai/letta-react 0.0.1
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 +117 -0
- package/dist/hooks/useAgentMessages/useAgentMessages.d.ts +27 -0
- package/dist/hooks/useAgentMessages/useAgentMessages.js +217 -0
- package/dist/hooks/useAgentState/useAgentState.d.ts +13 -0
- package/dist/hooks/useAgentState/useAgentState.js +46 -0
- package/dist/hooks/useCachedState/useCachedState.d.ts +2 -0
- package/dist/hooks/useCachedState/useCachedState.js +19 -0
- package/dist/hooks/useGlobalLettaConfig/useGlobalLettaConfig.d.ts +17 -0
- package/dist/hooks/useGlobalLettaConfig/useGlobalLettaConfig.js +22 -0
- package/dist/hooks/useLettaClient/useLettaClient.d.ts +2 -0
- package/dist/hooks/useLettaClient/useLettaClient.js +8 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/types.d.ts +5 -0
- package/dist/types.js +1 -0
- package/eslint.config.mjs +3 -0
- package/examples/view-and-send-messages/package-lock.json +1020 -0
- package/examples/view-and-send-messages/package.json +15 -0
- package/examples/view-and-send-messages/src/App.css +24 -0
- package/examples/view-and-send-messages/src/App.tsx +92 -0
- package/examples/view-and-send-messages/src/client.tsx +34 -0
- package/examples/view-and-send-messages/src/index.html +13 -0
- package/examples/view-and-send-messages/tsconfig.json +21 -0
- package/examples/view-and-send-messages/vite.config.mts +6 -0
- package/hooks/useAgentMessages/useAgentMessages.d.ts +27 -0
- package/hooks/useAgentMessages/useAgentMessages.js +217 -0
- package/hooks/useAgentState/useAgentState.d.ts +13 -0
- package/hooks/useAgentState/useAgentState.js +46 -0
- package/hooks/useCachedState/useCachedState.d.ts +2 -0
- package/hooks/useCachedState/useCachedState.js +19 -0
- package/hooks/useGlobalLettaConfig/useGlobalLettaConfig.d.ts +17 -0
- package/hooks/useGlobalLettaConfig/useGlobalLettaConfig.js +22 -0
- package/hooks/useLettaClient/useLettaClient.d.ts +2 -0
- package/hooks/useLettaClient/useLettaClient.js +8 -0
- package/index.d.ts +3 -0
- package/index.js +3 -0
- package/jest.config.ts +10 -0
- package/package.json +39 -0
- package/project.json +20 -0
- package/src/hooks/useAgentMessages/useAgentMessages.ts +329 -0
- package/src/hooks/useAgentState/useAgentState.ts +55 -0
- package/src/hooks/useCachedState/useCachedState.ts +30 -0
- package/src/hooks/useGlobalLettaConfig/useGlobalLettaConfig.tsx +49 -0
- package/src/hooks/useLettaClient/useLettaClient.ts +17 -0
- package/src/index.ts +3 -0
- package/src/types.ts +6 -0
- package/tsconfig.app.json +10 -0
- package/tsconfig.json +16 -0
- package/tsconfig.spec.json +15 -0
- package/types.d.ts +5 -0
- package/types.js +1 -0
package/README.md
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
# Letta React
|
2
|
+
|
3
|
+
A Letta react library full of the hooks you need to talk to Letta instantly
|
4
|
+
|
5
|
+
## Documentation
|
6
|
+
|
7
|
+
📚[Letta React Documentation](https://docs.letta.com/guides/letta-react)
|
8
|
+
|
9
|
+
### Minimal Example
|
10
|
+
|
11
|
+
#### Server-side configuration
|
12
|
+
|
13
|
+
##### Local Letta Instance
|
14
|
+
|
15
|
+
First setup Letta server, [instructions here](https://docs.letta.com/quickstart)
|
16
|
+
|
17
|
+
Add the following environment variable to your environment to avoid CORS errors
|
18
|
+
|
19
|
+
```bash
|
20
|
+
export ACCEPTABLE_ORIGINS=your server url
|
21
|
+
```
|
22
|
+
|
23
|
+
Then start your server.
|
24
|
+
|
25
|
+
##### Cloud/Secure Setups
|
26
|
+
|
27
|
+
Setup a proxy server, below we are using [`express`](https://www.npmjs.com/package/express), [`http-proxy-middleware`](https://www.npmjs.com/package/http-proxy-middleware) and [`cors`](https://www.npmjs.com/package/cors)
|
28
|
+
|
29
|
+
```
|
30
|
+
// typescript
|
31
|
+
|
32
|
+
import * as express from 'express';
|
33
|
+
import type { Request, Response, NextFunction } from 'express';
|
34
|
+
import cors from 'cors';
|
35
|
+
|
36
|
+
import { createProxyMiddleware } from 'http-proxy-middleware';
|
37
|
+
import type { Filter, Options, RequestHandler } from 'http-proxy-middleware';
|
38
|
+
|
39
|
+
const app = express();
|
40
|
+
|
41
|
+
|
42
|
+
app.use(cors({
|
43
|
+
origin: process.env.YOUR_WEBSITE_URL
|
44
|
+
}))
|
45
|
+
|
46
|
+
const lettaProxy = createProxyMiddleware<Request, Response>({
|
47
|
+
target: 'https://api.letta.com', // or your hosted url
|
48
|
+
changeOrigin: true,
|
49
|
+
headers: {
|
50
|
+
Authorization: 'Bearer ${process.env.LETTA_API_KEY}'
|
51
|
+
}
|
52
|
+
}),
|
53
|
+
|
54
|
+
app.use(lettaProxy);
|
55
|
+
|
56
|
+
app.listen(3000);
|
57
|
+
```
|
58
|
+
|
59
|
+
#### Client Side Usage
|
60
|
+
|
61
|
+
##### Set up the `<LettaProvider />`
|
62
|
+
|
63
|
+
Add the `<LettaProvider />` to the root of your application
|
64
|
+
|
65
|
+
```typescript jsx
|
66
|
+
import React from 'react';
|
67
|
+
import { StrictMode } from 'react';
|
68
|
+
import { createRoot } from 'react-dom/client';
|
69
|
+
import App from './App';
|
70
|
+
import { LettaProvider } from '../../src';
|
71
|
+
|
72
|
+
const domNode = document.getElementById('root');
|
73
|
+
const root = createRoot(domNode);
|
74
|
+
|
75
|
+
root.render(
|
76
|
+
<StrictMode>
|
77
|
+
<LettaProvider
|
78
|
+
options={{
|
79
|
+
baseUrl: `your-letta-api-server-location`,
|
80
|
+
}}
|
81
|
+
>
|
82
|
+
<App />
|
83
|
+
</LettaProvider>
|
84
|
+
</StrictMode>
|
85
|
+
);
|
86
|
+
```
|
87
|
+
|
88
|
+
##### Sending and Reading Messages `useAgentMessages`
|
89
|
+
|
90
|
+
Check out [this example](./examples/view-and-send-messages) for more detailed usage.
|
91
|
+
|
92
|
+
```typescript jsx
|
93
|
+
const {
|
94
|
+
messages,
|
95
|
+
isLoading,
|
96
|
+
isFetching,
|
97
|
+
isLoadingError,
|
98
|
+
sendMessage,
|
99
|
+
isSending,
|
100
|
+
sendingError,
|
101
|
+
isSendingError,
|
102
|
+
fetchOlderMessages,
|
103
|
+
hasOlderMessages,
|
104
|
+
} = useAgentMessages({
|
105
|
+
agentId: `your-agent-id`,
|
106
|
+
});
|
107
|
+
```
|
108
|
+
|
109
|
+
##### Getting Agent State
|
110
|
+
|
111
|
+
Check out [this example](./examples/view-and-send-messages) for more detailed usage.
|
112
|
+
|
113
|
+
```typescript jsx
|
114
|
+
const { agentState, error, isLoading, refresh } = agentState({
|
115
|
+
agentId: `your-agent-id`,
|
116
|
+
});
|
117
|
+
```
|
@@ -0,0 +1,27 @@
|
|
1
|
+
import { LettaClient, type Letta } from '@letta-ai/letta-client';
|
2
|
+
import type { LettaRequest } from '@letta-ai/letta-client/api/types/LettaRequest';
|
3
|
+
import type { MessagesListRequest } from '@letta-ai/letta-client/api/resources/agents';
|
4
|
+
interface UseAgentOptions {
|
5
|
+
client?: LettaClient.Options;
|
6
|
+
agentId: string;
|
7
|
+
limit?: number;
|
8
|
+
messageOptions?: Omit<MessagesListRequest, 'after' | 'before' | 'limit'>;
|
9
|
+
method?: 'stream' | 'basic';
|
10
|
+
}
|
11
|
+
interface SendMessagePayload {
|
12
|
+
messages: LettaRequest['messages'];
|
13
|
+
}
|
14
|
+
export declare function useAgentMessages(options: UseAgentOptions): {
|
15
|
+
messages: Letta.LettaMessageUnion[];
|
16
|
+
isLoading: boolean;
|
17
|
+
isFetching: boolean;
|
18
|
+
isLoadingError: boolean;
|
19
|
+
loadingError: unknown;
|
20
|
+
sendMessage: (payload: SendMessagePayload) => Promise<void> | undefined;
|
21
|
+
isSending: boolean;
|
22
|
+
sendingError: unknown;
|
23
|
+
isSendingError: boolean;
|
24
|
+
fetchOlderMessages: () => Promise<void>;
|
25
|
+
hasOlderMessages: string | undefined;
|
26
|
+
};
|
27
|
+
export {};
|
@@ -0,0 +1,217 @@
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
8
|
+
});
|
9
|
+
};
|
10
|
+
var __asyncValues = (this && this.__asyncValues) || function (o) {
|
11
|
+
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
12
|
+
var m = o[Symbol.asyncIterator], i;
|
13
|
+
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
|
14
|
+
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
|
15
|
+
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
|
16
|
+
};
|
17
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
18
|
+
import { useCachedState } from '../useCachedState/useCachedState';
|
19
|
+
import { useLettaClient } from '../useLettaClient/useLettaClient';
|
20
|
+
function extendContent(content, nextContent) {
|
21
|
+
if (typeof content === 'string') {
|
22
|
+
if (typeof nextContent === 'string') {
|
23
|
+
return `${content}${nextContent}`;
|
24
|
+
}
|
25
|
+
else {
|
26
|
+
return `${content}${nextContent.join('')}`;
|
27
|
+
}
|
28
|
+
}
|
29
|
+
else {
|
30
|
+
if (typeof nextContent === 'string') {
|
31
|
+
return [...content, { text: nextContent, type: 'text' }];
|
32
|
+
}
|
33
|
+
else {
|
34
|
+
return [...content, ...nextContent];
|
35
|
+
}
|
36
|
+
}
|
37
|
+
}
|
38
|
+
export function useAgentMessages(options) {
|
39
|
+
const { client = {}, method = 'stream', messageOptions = {}, limit = 20, agentId, } = options;
|
40
|
+
const localClient = useLettaClient(client);
|
41
|
+
const [localMessages, setLocalMessages] = useCachedState(`messages-${agentId}`, {
|
42
|
+
messages: [],
|
43
|
+
});
|
44
|
+
const hasInitialLoaded = useRef(false);
|
45
|
+
const [isLoading, setIsLoading] = useState(true);
|
46
|
+
const [isFetching, setIsFetching] = useState(false);
|
47
|
+
const [loadingError, setLoadingError] = useState(null);
|
48
|
+
const [isSending, setIsSending] = useState(false);
|
49
|
+
const [sendingError, setSendingError] = useState(null);
|
50
|
+
const sendNonStreamedMessage = useCallback(function sendNonStreamedMessage(sendMessagePayload) {
|
51
|
+
return __awaiter(this, void 0, void 0, function* () {
|
52
|
+
try {
|
53
|
+
setIsSending(true);
|
54
|
+
setSendingError(null);
|
55
|
+
const response = yield localClient.agents.messages.create(agentId, Object.assign(Object.assign({}, sendMessagePayload), messageOptions));
|
56
|
+
setLocalMessages((prevState) => (Object.assign(Object.assign({}, prevState), { messages: [...response.messages, ...prevState.messages] })));
|
57
|
+
}
|
58
|
+
catch (e) {
|
59
|
+
setSendingError(e);
|
60
|
+
}
|
61
|
+
finally {
|
62
|
+
setIsSending(false);
|
63
|
+
}
|
64
|
+
});
|
65
|
+
}, [localClient]);
|
66
|
+
const sendStreamedMessage = useCallback(function sendStreamedMessage(sendMessagePayload) {
|
67
|
+
return __awaiter(this, void 0, void 0, function* () {
|
68
|
+
var _a, e_1, _b, _c;
|
69
|
+
try {
|
70
|
+
setIsSending(true);
|
71
|
+
setSendingError(null);
|
72
|
+
const response = yield localClient.agents.messages.createStream(agentId, Object.assign(Object.assign(Object.assign({}, sendMessagePayload), messageOptions), { streamTokens: true }));
|
73
|
+
try {
|
74
|
+
for (var _d = true, response_1 = __asyncValues(response), response_1_1; response_1_1 = yield response_1.next(), _a = response_1_1.done, !_a; _d = true) {
|
75
|
+
_c = response_1_1.value;
|
76
|
+
_d = false;
|
77
|
+
const nextMessage = _c;
|
78
|
+
if (nextMessage.messageType === 'usage_statistics') {
|
79
|
+
return;
|
80
|
+
}
|
81
|
+
// @ts-expect-error - this is a correct lookup, id does exist
|
82
|
+
if (!(nextMessage === null || nextMessage === void 0 ? void 0 : nextMessage.id)) {
|
83
|
+
return;
|
84
|
+
}
|
85
|
+
setLocalMessages((prevState) => {
|
86
|
+
let hasExistingMessage = false;
|
87
|
+
const nextMessages = prevState.messages.map((prevMessage) => {
|
88
|
+
if (nextMessage.messageType === 'usage_statistics') {
|
89
|
+
return prevMessage;
|
90
|
+
}
|
91
|
+
// @ts-expect-error - this is a correct lookup, id does exist
|
92
|
+
if (!(prevMessage === null || prevMessage === void 0 ? void 0 : prevMessage.id) || !(nextMessage === null || nextMessage === void 0 ? void 0 : nextMessage.id)) {
|
93
|
+
return prevMessage;
|
94
|
+
}
|
95
|
+
// @ts-expect-error - this is a correct lookup, id does exist
|
96
|
+
if (prevMessage.id !== nextMessage.id) {
|
97
|
+
return prevMessage;
|
98
|
+
}
|
99
|
+
if (nextMessage.messageType === 'reasoning_message' &&
|
100
|
+
prevMessage.messageType === 'reasoning_message') {
|
101
|
+
hasExistingMessage = true;
|
102
|
+
return Object.assign(Object.assign(Object.assign({}, prevMessage), nextMessage), { reasoning: `${prevMessage.reasoning}${nextMessage.reasoning}` });
|
103
|
+
}
|
104
|
+
if (nextMessage.messageType === 'system_message' &&
|
105
|
+
prevMessage.messageType === 'system_message') {
|
106
|
+
hasExistingMessage = true;
|
107
|
+
return Object.assign(Object.assign(Object.assign({}, prevMessage), nextMessage), { content: extendContent(prevMessage.content, nextMessage.content) });
|
108
|
+
}
|
109
|
+
if (nextMessage.messageType === 'user_message' &&
|
110
|
+
prevMessage.messageType === 'user_message') {
|
111
|
+
hasExistingMessage = true;
|
112
|
+
return Object.assign(Object.assign(Object.assign({}, prevMessage), nextMessage), { content: extendContent(prevMessage.content, nextMessage.content) });
|
113
|
+
}
|
114
|
+
if (nextMessage.messageType === 'assistant_message' &&
|
115
|
+
prevMessage.messageType === 'assistant_message') {
|
116
|
+
hasExistingMessage = true;
|
117
|
+
return Object.assign(Object.assign(Object.assign({}, prevMessage), nextMessage), { content: extendContent(prevMessage.content, nextMessage.content) });
|
118
|
+
}
|
119
|
+
if (nextMessage.messageType === 'tool_call_message' &&
|
120
|
+
prevMessage.messageType === 'tool_call_message') {
|
121
|
+
hasExistingMessage = true;
|
122
|
+
return Object.assign(Object.assign({}, prevMessage), nextMessage);
|
123
|
+
}
|
124
|
+
if (nextMessage.messageType === 'tool_return_message' &&
|
125
|
+
prevMessage.messageType === 'tool_return_message') {
|
126
|
+
hasExistingMessage = true;
|
127
|
+
return Object.assign(Object.assign({}, prevMessage), nextMessage);
|
128
|
+
}
|
129
|
+
return prevMessage;
|
130
|
+
});
|
131
|
+
return Object.assign(Object.assign({}, prevState), { messages: [
|
132
|
+
...nextMessages,
|
133
|
+
...(!hasExistingMessage
|
134
|
+
? [
|
135
|
+
Object.assign({}, nextMessage),
|
136
|
+
]
|
137
|
+
: []),
|
138
|
+
] });
|
139
|
+
});
|
140
|
+
}
|
141
|
+
}
|
142
|
+
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
143
|
+
finally {
|
144
|
+
try {
|
145
|
+
if (!_d && !_a && (_b = response_1.return)) yield _b.call(response_1);
|
146
|
+
}
|
147
|
+
finally { if (e_1) throw e_1.error; }
|
148
|
+
}
|
149
|
+
}
|
150
|
+
catch (e) {
|
151
|
+
setSendingError(e);
|
152
|
+
}
|
153
|
+
finally {
|
154
|
+
setIsSending(false);
|
155
|
+
}
|
156
|
+
});
|
157
|
+
}, [localClient]);
|
158
|
+
const sendMessage = useCallback(function sendMessage(payload) {
|
159
|
+
if (isSending) {
|
160
|
+
return;
|
161
|
+
}
|
162
|
+
if (method === 'stream') {
|
163
|
+
return sendStreamedMessage(payload);
|
164
|
+
}
|
165
|
+
return sendNonStreamedMessage(payload);
|
166
|
+
}, [method, isSending, sendStreamedMessage, sendNonStreamedMessage]);
|
167
|
+
const getMessages = useCallback(function getMessages(before) {
|
168
|
+
return __awaiter(this, void 0, void 0, function* () {
|
169
|
+
try {
|
170
|
+
if (isFetching) {
|
171
|
+
return;
|
172
|
+
}
|
173
|
+
setLoadingError(null);
|
174
|
+
setIsFetching(true);
|
175
|
+
const messages = yield localClient.agents.messages.list(agentId, Object.assign({ before, limit: limit + 1 }, messageOptions));
|
176
|
+
const messagesToAdd = messages.slice(1, messages.length);
|
177
|
+
const nextCursor = messages.length > limit ? messages[0] : undefined;
|
178
|
+
setLocalMessages((prevState) => (Object.assign(Object.assign({}, prevState), { messages: [...messagesToAdd, ...prevState.messages], nextCursor: nextCursor === null || nextCursor === void 0 ? void 0 : nextCursor.id })));
|
179
|
+
}
|
180
|
+
catch (e) {
|
181
|
+
setLoadingError(e);
|
182
|
+
}
|
183
|
+
finally {
|
184
|
+
setIsFetching(false);
|
185
|
+
setIsLoading(false);
|
186
|
+
}
|
187
|
+
});
|
188
|
+
}, [localClient, isFetching]);
|
189
|
+
const fetchOlderMessages = useCallback(() => __awaiter(this, void 0, void 0, function* () {
|
190
|
+
const nextCursor = localMessages.nextCursor;
|
191
|
+
if (!nextCursor) {
|
192
|
+
return;
|
193
|
+
}
|
194
|
+
return getMessages(nextCursor);
|
195
|
+
}), [getMessages]);
|
196
|
+
useEffect(() => {
|
197
|
+
if (hasInitialLoaded.current) {
|
198
|
+
return;
|
199
|
+
}
|
200
|
+
hasInitialLoaded.current = true;
|
201
|
+
setIsLoading(true);
|
202
|
+
getMessages();
|
203
|
+
}, []);
|
204
|
+
return {
|
205
|
+
messages: localMessages.messages,
|
206
|
+
isLoading,
|
207
|
+
isFetching,
|
208
|
+
isLoadingError: !!loadingError,
|
209
|
+
loadingError,
|
210
|
+
sendMessage,
|
211
|
+
isSending,
|
212
|
+
sendingError,
|
213
|
+
isSendingError: !!sendingError,
|
214
|
+
fetchOlderMessages,
|
215
|
+
hasOlderMessages: localMessages.nextCursor,
|
216
|
+
};
|
217
|
+
}
|
@@ -0,0 +1,13 @@
|
|
1
|
+
import type { LettaClient } from '@letta-ai/letta-client';
|
2
|
+
import type { AgentState } from '@letta-ai/letta-client/api';
|
3
|
+
interface UseAgentStateOptions {
|
4
|
+
client?: LettaClient.Options;
|
5
|
+
agentId: string;
|
6
|
+
}
|
7
|
+
export declare function useAgentState(options: UseAgentStateOptions): {
|
8
|
+
isLoading: boolean;
|
9
|
+
error: unknown;
|
10
|
+
agentState: AgentState | undefined;
|
11
|
+
refresh: () => Promise<void>;
|
12
|
+
};
|
13
|
+
export {};
|
@@ -0,0 +1,46 @@
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
8
|
+
});
|
9
|
+
};
|
10
|
+
import { useLettaClient } from '../useLettaClient/useLettaClient';
|
11
|
+
import { useCachedState } from '../useCachedState/useCachedState';
|
12
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
13
|
+
export function useAgentState(options) {
|
14
|
+
const { client, agentId } = options;
|
15
|
+
const localClient = useLettaClient(client);
|
16
|
+
const [localState, setLocalState] = useCachedState(`agent-state-${agentId}`, undefined);
|
17
|
+
const [isLoading, setIsLoading] = useState(true);
|
18
|
+
const [loadingError, setLoadingError] = useState(null);
|
19
|
+
const hasInitialLoaded = useRef(false);
|
20
|
+
const getAgentState = useCallback(() => __awaiter(this, void 0, void 0, function* () {
|
21
|
+
try {
|
22
|
+
const state = yield localClient.agents.retrieve(agentId);
|
23
|
+
setLocalState(state);
|
24
|
+
}
|
25
|
+
catch (error) {
|
26
|
+
setLoadingError(error);
|
27
|
+
}
|
28
|
+
finally {
|
29
|
+
setIsLoading(false);
|
30
|
+
}
|
31
|
+
}), [agentId, localClient, setLocalState]);
|
32
|
+
useEffect(() => {
|
33
|
+
if (hasInitialLoaded.current) {
|
34
|
+
return;
|
35
|
+
}
|
36
|
+
hasInitialLoaded.current = true;
|
37
|
+
setIsLoading(true);
|
38
|
+
getAgentState();
|
39
|
+
}, []);
|
40
|
+
return {
|
41
|
+
isLoading,
|
42
|
+
error: loadingError,
|
43
|
+
agentState: localState,
|
44
|
+
refresh: getAgentState,
|
45
|
+
};
|
46
|
+
}
|
@@ -0,0 +1,19 @@
|
|
1
|
+
import { useGlobalLettaConfig } from '../useGlobalLettaConfig/useGlobalLettaConfig';
|
2
|
+
import { useState } from 'react';
|
3
|
+
export function useCachedState(key, defaultValue) {
|
4
|
+
const { isProviderSet, cachedData, updateCache } = useGlobalLettaConfig();
|
5
|
+
const [localState, setLocalState] = useState(defaultValue);
|
6
|
+
if (!isProviderSet) {
|
7
|
+
return [localState, setLocalState];
|
8
|
+
}
|
9
|
+
return [
|
10
|
+
(cachedData === null || cachedData === void 0 ? void 0 : cachedData[key]) || defaultValue,
|
11
|
+
(value) => {
|
12
|
+
updateCache((prevState) => {
|
13
|
+
return Object.assign(Object.assign({}, prevState), { [key]: typeof value === 'function'
|
14
|
+
? value((prevState === null || prevState === void 0 ? void 0 : prevState[key]) || defaultValue)
|
15
|
+
: value });
|
16
|
+
});
|
17
|
+
},
|
18
|
+
];
|
19
|
+
}
|
@@ -0,0 +1,17 @@
|
|
1
|
+
import React, { Dispatch, SetStateAction } from 'react';
|
2
|
+
import { LettaClient } from '@letta-ai/letta-client';
|
3
|
+
import { type ReactNode } from 'react';
|
4
|
+
type CachedData = Record<string, any>;
|
5
|
+
interface LettaProviderState {
|
6
|
+
isProviderSet?: boolean;
|
7
|
+
state: LettaClient.Options;
|
8
|
+
cachedData: CachedData;
|
9
|
+
updateCache: Dispatch<SetStateAction<CachedData>>;
|
10
|
+
}
|
11
|
+
interface LettaProviderProps {
|
12
|
+
options: LettaClient.Options;
|
13
|
+
children: ReactNode;
|
14
|
+
}
|
15
|
+
export declare function LettaProvider(props: LettaProviderProps): React.JSX.Element;
|
16
|
+
export declare function useGlobalLettaConfig(): LettaProviderState;
|
17
|
+
export {};
|
@@ -0,0 +1,22 @@
|
|
1
|
+
import React, { useState } from 'react';
|
2
|
+
import { createContext, useMemo, useContext } from 'react';
|
3
|
+
const LettaContext = createContext({
|
4
|
+
state: {},
|
5
|
+
cachedData: {},
|
6
|
+
updateCache: () => {
|
7
|
+
return;
|
8
|
+
},
|
9
|
+
});
|
10
|
+
export function LettaProvider(props) {
|
11
|
+
const [cachedData, updateCache] = useState({});
|
12
|
+
const state = useMemo(() => ({
|
13
|
+
state: props.options,
|
14
|
+
cachedData,
|
15
|
+
updateCache,
|
16
|
+
isProviderSet: true,
|
17
|
+
}), [props.options, updateCache, cachedData]);
|
18
|
+
return (React.createElement(LettaContext.Provider, { value: state }, props.children));
|
19
|
+
}
|
20
|
+
export function useGlobalLettaConfig() {
|
21
|
+
return useContext(LettaContext);
|
22
|
+
}
|
@@ -0,0 +1,8 @@
|
|
1
|
+
import { useState } from 'react';
|
2
|
+
import { LettaClient } from '@letta-ai/letta-client';
|
3
|
+
import { useGlobalLettaConfig } from '../useGlobalLettaConfig/useGlobalLettaConfig';
|
4
|
+
export function useLettaClient(localOptions = {}) {
|
5
|
+
const globalClient = useGlobalLettaConfig();
|
6
|
+
const [localClient] = useState(() => new LettaClient(Object.assign(Object.assign({}, globalClient.state), localOptions)));
|
7
|
+
return localClient;
|
8
|
+
}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
package/dist/types.d.ts
ADDED
package/dist/types.js
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
export {};
|