@bty/feed_app-runtime-sdk 0.0.5 → 0.0.7
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 +7 -17
- package/dist/ai/index.d.ts +276 -13
- package/dist/ai/index.js +3 -3
- package/dist/react/index.d.ts +1 -45
- package/dist/react/index.js +1 -3
- package/package.json +3 -2
- package/dist/errors-C0zJPCCU.d.ts +0 -295
package/README.md
CHANGED
|
@@ -34,17 +34,14 @@ environment they resolve to empty values instead of touching `window`.
|
|
|
34
34
|
## AI
|
|
35
35
|
|
|
36
36
|
```ts
|
|
37
|
-
import { configureRuntime, openai
|
|
37
|
+
import { configureRuntime, openai } from '@bty/feed_app-runtime-sdk/ai'
|
|
38
38
|
|
|
39
39
|
configureRuntime({
|
|
40
40
|
apiBaseUrl: 'https://example.com',
|
|
41
|
-
projectId: 'your-project-id',
|
|
42
41
|
})
|
|
43
42
|
|
|
44
|
-
const availableModels = await models.list()
|
|
45
|
-
|
|
46
43
|
const stream = await openai.chat.completions.create({
|
|
47
|
-
model:
|
|
44
|
+
model: 'gpt-5.4',
|
|
48
45
|
messages: [{ role: 'user', content: 'Hello' }],
|
|
49
46
|
stream: true,
|
|
50
47
|
})
|
|
@@ -64,7 +61,6 @@ The AI entry supports:
|
|
|
64
61
|
- Image generation
|
|
65
62
|
- Text-to-speech
|
|
66
63
|
- Video generation
|
|
67
|
-
- Model listing
|
|
68
64
|
- `AbortSignal` cancellation
|
|
69
65
|
- Structured AI errors
|
|
70
66
|
|
|
@@ -92,30 +88,24 @@ try {
|
|
|
92
88
|
## React
|
|
93
89
|
|
|
94
90
|
```tsx
|
|
95
|
-
import {
|
|
96
|
-
useAiChat,
|
|
97
|
-
useAuthToken,
|
|
98
|
-
useUserInfo,
|
|
99
|
-
} from '@bty/feed_app-runtime-sdk/react'
|
|
91
|
+
import { useAuthToken, useUserInfo } from '@bty/feed_app-runtime-sdk/react'
|
|
100
92
|
|
|
101
93
|
export function App() {
|
|
102
94
|
const { token, loading: tokenLoading } = useAuthToken()
|
|
103
95
|
const { user } = useUserInfo()
|
|
104
|
-
const chat = useAiChat({ model: 'gpt-5.4' })
|
|
105
96
|
|
|
106
97
|
return (
|
|
107
98
|
<main>
|
|
108
99
|
<p>{tokenLoading ? 'Loading...' : (user?.username ?? user?.nickname)}</p>
|
|
109
|
-
<button onClick={() => chat.send('Hello')}>Send</button>
|
|
110
|
-
<button onClick={chat.stop} disabled={!chat.loading}>Stop</button>
|
|
111
|
-
{chat.messages.map((message, index) => (
|
|
112
|
-
<p key={index}>{String(message.content)}</p>
|
|
113
|
-
))}
|
|
114
100
|
</main>
|
|
115
101
|
)
|
|
116
102
|
}
|
|
117
103
|
```
|
|
118
104
|
|
|
105
|
+
For chat / image / TTS / video, call `openai` / `anthropic` from `/ai` directly
|
|
106
|
+
and wire your own loading / cancel / error state. Product-specific chat UX
|
|
107
|
+
varies enough that a generic hook tends to leak abstractions.
|
|
108
|
+
|
|
119
109
|
React is an optional peer dependency. Projects that do not import the `/react`
|
|
120
110
|
entry do not need to install React.
|
|
121
111
|
|
package/dist/ai/index.d.ts
CHANGED
|
@@ -1,5 +1,244 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
interface ApiRequestOptions {
|
|
2
|
+
/** AbortSignal — propagated through fetch into the upstream stream. */
|
|
3
|
+
signal?: AbortSignal;
|
|
4
|
+
/** Extra HTTP headers merged on top of SDK-injected ones. */
|
|
5
|
+
headers?: Record<string, string>;
|
|
6
|
+
}
|
|
7
|
+
interface ChatMessage {
|
|
8
|
+
role: "system" | "user" | "assistant" | "tool";
|
|
9
|
+
content: string | ChatContentPart[];
|
|
10
|
+
name?: string;
|
|
11
|
+
tool_call_id?: string;
|
|
12
|
+
tool_calls?: ChatToolCall[];
|
|
13
|
+
[key: string]: unknown;
|
|
14
|
+
}
|
|
15
|
+
interface ChatContentPart {
|
|
16
|
+
type: "text" | "image_url" | "input_audio";
|
|
17
|
+
text?: string;
|
|
18
|
+
image_url?: {
|
|
19
|
+
url: string;
|
|
20
|
+
detail?: "low" | "high" | "auto";
|
|
21
|
+
};
|
|
22
|
+
input_audio?: {
|
|
23
|
+
data: string;
|
|
24
|
+
format: "wav" | "mp3";
|
|
25
|
+
};
|
|
26
|
+
[key: string]: unknown;
|
|
27
|
+
}
|
|
28
|
+
interface ChatToolCall {
|
|
29
|
+
id: string;
|
|
30
|
+
type: "function";
|
|
31
|
+
function: {
|
|
32
|
+
name: string;
|
|
33
|
+
arguments: string;
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
interface ChatTool {
|
|
37
|
+
type: "function";
|
|
38
|
+
function: {
|
|
39
|
+
name: string;
|
|
40
|
+
description?: string;
|
|
41
|
+
parameters?: Record<string, unknown>;
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
interface ChatCompletionCreateParams extends ApiRequestOptions {
|
|
45
|
+
model: string;
|
|
46
|
+
messages: ChatMessage[];
|
|
47
|
+
stream?: boolean;
|
|
48
|
+
temperature?: number;
|
|
49
|
+
top_p?: number;
|
|
50
|
+
max_tokens?: number;
|
|
51
|
+
tools?: ChatTool[];
|
|
52
|
+
tool_choice?: "auto" | "none" | "required" | {
|
|
53
|
+
type: string;
|
|
54
|
+
function: {
|
|
55
|
+
name: string;
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
response_format?: {
|
|
59
|
+
type: "text" | "json_object" | "json_schema";
|
|
60
|
+
[key: string]: unknown;
|
|
61
|
+
};
|
|
62
|
+
[key: string]: unknown;
|
|
63
|
+
}
|
|
64
|
+
interface ChatCompletion {
|
|
65
|
+
id: string;
|
|
66
|
+
object: "chat.completion";
|
|
67
|
+
created: number;
|
|
68
|
+
model: string;
|
|
69
|
+
choices: {
|
|
70
|
+
index: number;
|
|
71
|
+
message: {
|
|
72
|
+
role: "assistant";
|
|
73
|
+
content: string | null;
|
|
74
|
+
tool_calls?: ChatToolCall[];
|
|
75
|
+
};
|
|
76
|
+
finish_reason: string | null;
|
|
77
|
+
}[];
|
|
78
|
+
usage?: {
|
|
79
|
+
prompt_tokens: number;
|
|
80
|
+
completion_tokens: number;
|
|
81
|
+
total_tokens: number;
|
|
82
|
+
};
|
|
83
|
+
[key: string]: unknown;
|
|
84
|
+
}
|
|
85
|
+
interface ChatCompletionChunk {
|
|
86
|
+
id: string;
|
|
87
|
+
object: "chat.completion.chunk";
|
|
88
|
+
created: number;
|
|
89
|
+
model: string;
|
|
90
|
+
choices: {
|
|
91
|
+
index: number;
|
|
92
|
+
delta: {
|
|
93
|
+
role?: "assistant";
|
|
94
|
+
content?: string;
|
|
95
|
+
tool_calls?: Partial<ChatToolCall>[];
|
|
96
|
+
};
|
|
97
|
+
finish_reason: string | null;
|
|
98
|
+
}[];
|
|
99
|
+
[key: string]: unknown;
|
|
100
|
+
}
|
|
101
|
+
interface ImageGenerateParams extends ApiRequestOptions {
|
|
102
|
+
prompt: string;
|
|
103
|
+
model?: string;
|
|
104
|
+
n?: number;
|
|
105
|
+
size?: string;
|
|
106
|
+
quality?: "standard" | "hd";
|
|
107
|
+
style?: "vivid" | "natural";
|
|
108
|
+
response_format?: "url" | "b64_json";
|
|
109
|
+
[key: string]: unknown;
|
|
110
|
+
}
|
|
111
|
+
interface ImageGenerateResponse {
|
|
112
|
+
created: number;
|
|
113
|
+
data: {
|
|
114
|
+
url?: string;
|
|
115
|
+
b64_json?: string;
|
|
116
|
+
revised_prompt?: string;
|
|
117
|
+
}[];
|
|
118
|
+
}
|
|
119
|
+
interface AudioSpeechCreateParams extends ApiRequestOptions {
|
|
120
|
+
model: string;
|
|
121
|
+
input: string;
|
|
122
|
+
voice: string;
|
|
123
|
+
response_format?: "mp3" | "opus" | "aac" | "flac" | "wav" | "pcm";
|
|
124
|
+
speed?: number;
|
|
125
|
+
[key: string]: unknown;
|
|
126
|
+
}
|
|
127
|
+
interface VideoGenerateParams extends ApiRequestOptions {
|
|
128
|
+
prompt: string;
|
|
129
|
+
model?: string;
|
|
130
|
+
duration?: number;
|
|
131
|
+
size?: string;
|
|
132
|
+
[key: string]: unknown;
|
|
133
|
+
}
|
|
134
|
+
interface VideoGenerateResponse {
|
|
135
|
+
created: number;
|
|
136
|
+
data: {
|
|
137
|
+
url?: string;
|
|
138
|
+
b64_json?: string;
|
|
139
|
+
}[];
|
|
140
|
+
[key: string]: unknown;
|
|
141
|
+
}
|
|
142
|
+
interface AnthropicMessage {
|
|
143
|
+
role: "user" | "assistant";
|
|
144
|
+
content: string | AnthropicContentBlock[];
|
|
145
|
+
}
|
|
146
|
+
type AnthropicContentBlock = {
|
|
147
|
+
type: "text";
|
|
148
|
+
text: string;
|
|
149
|
+
} | {
|
|
150
|
+
type: "image";
|
|
151
|
+
source: {
|
|
152
|
+
type: "base64";
|
|
153
|
+
media_type: "image/jpeg" | "image/png" | "image/gif" | "image/webp";
|
|
154
|
+
data: string;
|
|
155
|
+
};
|
|
156
|
+
} | {
|
|
157
|
+
type: "tool_use";
|
|
158
|
+
id: string;
|
|
159
|
+
name: string;
|
|
160
|
+
input: Record<string, unknown>;
|
|
161
|
+
} | {
|
|
162
|
+
type: "tool_result";
|
|
163
|
+
tool_use_id: string;
|
|
164
|
+
content: string | AnthropicContentBlock[];
|
|
165
|
+
};
|
|
166
|
+
interface AnthropicTool {
|
|
167
|
+
name: string;
|
|
168
|
+
description?: string;
|
|
169
|
+
input_schema: Record<string, unknown>;
|
|
170
|
+
}
|
|
171
|
+
interface MessagesCreateParams extends ApiRequestOptions {
|
|
172
|
+
model: string;
|
|
173
|
+
messages: AnthropicMessage[];
|
|
174
|
+
max_tokens: number;
|
|
175
|
+
system?: string | AnthropicContentBlock[];
|
|
176
|
+
stream?: boolean;
|
|
177
|
+
temperature?: number;
|
|
178
|
+
top_p?: number;
|
|
179
|
+
top_k?: number;
|
|
180
|
+
tools?: AnthropicTool[];
|
|
181
|
+
tool_choice?: {
|
|
182
|
+
type: "auto" | "any" | "tool";
|
|
183
|
+
name?: string;
|
|
184
|
+
};
|
|
185
|
+
stop_sequences?: string[];
|
|
186
|
+
[key: string]: unknown;
|
|
187
|
+
}
|
|
188
|
+
interface AnthropicMessageResponse {
|
|
189
|
+
id: string;
|
|
190
|
+
type: "message";
|
|
191
|
+
role: "assistant";
|
|
192
|
+
model: string;
|
|
193
|
+
content: AnthropicContentBlock[];
|
|
194
|
+
stop_reason: string | null;
|
|
195
|
+
stop_sequence: string | null;
|
|
196
|
+
usage: {
|
|
197
|
+
input_tokens: number;
|
|
198
|
+
output_tokens: number;
|
|
199
|
+
};
|
|
200
|
+
[key: string]: unknown;
|
|
201
|
+
}
|
|
202
|
+
type AnthropicStreamEvent = {
|
|
203
|
+
type: "message_start";
|
|
204
|
+
message: AnthropicMessageResponse;
|
|
205
|
+
} | {
|
|
206
|
+
type: "content_block_start";
|
|
207
|
+
index: number;
|
|
208
|
+
content_block: AnthropicContentBlock;
|
|
209
|
+
} | {
|
|
210
|
+
type: "content_block_delta";
|
|
211
|
+
index: number;
|
|
212
|
+
delta: {
|
|
213
|
+
type: "text_delta";
|
|
214
|
+
text: string;
|
|
215
|
+
} | {
|
|
216
|
+
type: "input_json_delta";
|
|
217
|
+
partial_json: string;
|
|
218
|
+
};
|
|
219
|
+
} | {
|
|
220
|
+
type: "content_block_stop";
|
|
221
|
+
index: number;
|
|
222
|
+
} | {
|
|
223
|
+
type: "message_delta";
|
|
224
|
+
delta: {
|
|
225
|
+
stop_reason: string | null;
|
|
226
|
+
stop_sequence: string | null;
|
|
227
|
+
};
|
|
228
|
+
usage: {
|
|
229
|
+
output_tokens: number;
|
|
230
|
+
};
|
|
231
|
+
} | {
|
|
232
|
+
type: "message_stop";
|
|
233
|
+
} | {
|
|
234
|
+
type: "ping";
|
|
235
|
+
} | {
|
|
236
|
+
type: "error";
|
|
237
|
+
error: {
|
|
238
|
+
type: string;
|
|
239
|
+
message: string;
|
|
240
|
+
};
|
|
241
|
+
};
|
|
3
242
|
|
|
4
243
|
interface ChatCompletionsCreate {
|
|
5
244
|
(params: ChatCompletionCreateParams & {
|
|
@@ -54,19 +293,14 @@ declare const anthropic: {
|
|
|
54
293
|
};
|
|
55
294
|
};
|
|
56
295
|
|
|
57
|
-
interface ListOptions {
|
|
58
|
-
signal?: AbortSignal;
|
|
59
|
-
/** Re-fetch even when cache is warm. */
|
|
60
|
-
force?: boolean;
|
|
61
|
-
}
|
|
62
|
-
declare const models: {
|
|
63
|
-
list: (options?: ListOptions) => Promise<ModelInfo[]>;
|
|
64
|
-
};
|
|
65
|
-
|
|
66
296
|
interface RuntimeConfig {
|
|
67
297
|
/** Base URL for all reactus-backend calls. Trailing slash stripped. */
|
|
68
298
|
apiBaseUrl: string;
|
|
69
|
-
/**
|
|
299
|
+
/**
|
|
300
|
+
* Project id sent as `x-bty-app` on every AI call. The backend uses it to
|
|
301
|
+
* attribute usage / billing / quota per-project. Empty string suppresses
|
|
302
|
+
* the header — backend will then 4xx the request (no server-side default).
|
|
303
|
+
*/
|
|
70
304
|
projectId: string;
|
|
71
305
|
}
|
|
72
306
|
/**
|
|
@@ -75,4 +309,33 @@ interface RuntimeConfig {
|
|
|
75
309
|
*/
|
|
76
310
|
declare const configureRuntime: (cfg: Partial<RuntimeConfig>) => void;
|
|
77
311
|
|
|
78
|
-
|
|
312
|
+
type AiErrorCode = "auth_required" | "rate_limit" | "quota_exceeded" | "bad_input" | "server" | "network" | "aborted" | "unknown";
|
|
313
|
+
declare class AiError extends Error {
|
|
314
|
+
readonly status: number;
|
|
315
|
+
readonly code: AiErrorCode;
|
|
316
|
+
readonly body: unknown;
|
|
317
|
+
constructor(message: string, code: AiErrorCode, status: number, body?: unknown);
|
|
318
|
+
}
|
|
319
|
+
declare class AuthRequiredError extends AiError {
|
|
320
|
+
constructor(message?: string, body?: unknown);
|
|
321
|
+
}
|
|
322
|
+
declare class RateLimitError extends AiError {
|
|
323
|
+
constructor(message?: string, body?: unknown);
|
|
324
|
+
}
|
|
325
|
+
declare class QuotaExceededError extends AiError {
|
|
326
|
+
constructor(message?: string, body?: unknown);
|
|
327
|
+
}
|
|
328
|
+
declare class BadInputError extends AiError {
|
|
329
|
+
constructor(message: string, status?: number, body?: unknown);
|
|
330
|
+
}
|
|
331
|
+
declare class ServerError extends AiError {
|
|
332
|
+
constructor(message: string, status?: number, body?: unknown);
|
|
333
|
+
}
|
|
334
|
+
declare class NetworkError extends AiError {
|
|
335
|
+
constructor(message?: string, cause?: unknown);
|
|
336
|
+
}
|
|
337
|
+
declare class AbortedError extends AiError {
|
|
338
|
+
constructor(message?: string);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
export { AbortedError, AiError, type AiErrorCode, type AnthropicContentBlock, type AnthropicMessage, type AnthropicMessageResponse, type AnthropicStreamEvent, type AnthropicTool, type AudioSpeechCreateParams, AuthRequiredError, BadInputError, type ChatCompletion, type ChatCompletionChunk, type ChatCompletionCreateParams, type ChatContentPart, type ChatMessage, type ChatTool, type ChatToolCall, type ImageGenerateParams, type ImageGenerateResponse, type MessagesCreateParams, NetworkError, QuotaExceededError, RateLimitError, type RuntimeConfig, ServerError, type VideoGenerateParams, type VideoGenerateResponse, anthropic, configureRuntime, openai };
|
package/dist/ai/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var Y={version:"0.0.
|
|
2
|
-
`)};return r="",s=[],c};try{for(;;){let{done:c,value:p}=await t.read();if(c){let i=o();i&&(yield i);return}for(n+=
|
|
3
|
-
export{S as AbortedError,m as AiError,g as AuthRequiredError,
|
|
1
|
+
var Y={version:"0.0.7"};var A="/v1/feed-app/runtime/ai",U=`${A}/chat/completions`,H=`${A}/messages`,K=`${A}/images/generations`,X=`${A}/audio/speech`,W=`${A}/video/generations`,z="Authorization",Z="x-bty-extend",ee="x-bty-app",te=Y.version;var He=/\r\n|\r|\n/,Le=(()=>{let e=new TextDecoder;return (t,n)=>e.decode(t,{stream:n})})();async function*ne(e){let t=e.getReader(),n="",r="",s=[],o=()=>{if(s.length===0&&!r)return null;let c={event:r||"message",data:s.join(`
|
|
2
|
+
`)};return r="",s=[],c};try{for(;;){let{done:c,value:p}=await t.read();if(c){let i=o();i&&(yield i);return}for(n+=Le(p,!0);;){let i=He.exec(n);if(!i)break;let d=n.slice(0,i.index);if(n=n.slice(i.index+i[0].length),d===""){let f=o();f&&(yield f);continue}if(d.startsWith(":"))continue;let _=d.indexOf(":"),I=_===-1?d:d.slice(0,_),l=_===-1?"":d.slice(_+1);l.startsWith(" ")&&(l=l.slice(1)),I==="event"?r=l:I==="data"&&s.push(l);}}}finally{t.releaseLock();}}async function*re(e){for await(let t of ne(e)){if(t.data==="[DONE]")return;t.data&&(yield JSON.parse(t.data));}}async function*se(e){for await(let t of ne(e))t.data&&(yield JSON.parse(t.data));}var De="https://reactus-api.betteryeah.com",oe=e=>{try{let t=e();if(typeof t=="string"&&t.length>0)return t}catch{}},Be=()=>oe(()=>typeof __BTY_RUNTIME_API_BASE_URL__=="string"?__BTY_RUNTIME_API_BASE_URL__:void 0),Fe=()=>oe(()=>typeof __BTY_RUNTIME_PROJECT_ID__=="string"?__BTY_RUNTIME_PROJECT_ID__:void 0),L={apiBaseUrl:(Be()??De).replace(/\/+$/,""),projectId:Fe()??""},qe=e=>{L={...L,...e,...e.apiBaseUrl?{apiBaseUrl:e.apiBaseUrl.replace(/\/+$/,"")}:{}};},x=()=>L;var m=class extends Error{status;code;body;constructor(t,n,r,s=null){super(t),this.name="AiError",this.code=n,this.status=r,this.body=s;}},g=class extends m{constructor(t="Auth required",n=null){super(t,"auth_required",401,n),this.name="AuthRequiredError";}},P=class extends m{constructor(t="Rate limit exceeded",n=null){super(t,"rate_limit",429,n),this.name="RateLimitError";}},k=class extends m{constructor(t="Quota exceeded",n=null){super(t,"quota_exceeded",402,n),this.name="QuotaExceededError";}},O=class extends m{constructor(t,n=400,r=null){super(t,"bad_input",n,r),this.name="BadInputError";}},N=class extends m{constructor(t,n=500,r=null){super(t,"server",n,r),this.name="ServerError";}},y=class extends m{constructor(t="Network error",n){super(t,"network",-1,n),this.name="NetworkError";}},S=class extends m{constructor(t="Request aborted"){super(t,"aborted",-1,null),this.name="AbortedError";}},ie=e=>typeof e=="object"&&e!==null,je=(e,t)=>{if(typeof e=="string")return e||t;if(!ie(e))return t;let n=e.message;if(typeof n=="string"&&n.length>0)return n;let r=e.error;if(typeof r=="string"&&r.length>0)return r;if(ie(r)&&typeof r.message=="string"&&r.message.length>0)return r.message;let s=e.detail;return typeof s=="string"&&s.length>0?s:t},D=(e,t)=>{let n=je(t,`HTTP ${e}`);return e===401||e===403?new g(n,t):e===402?new k(n,t):e===429?new P(n,t):e>=400&&e<500?new O(n,e,t):e>=500?new N(n,e,t):new m(n,"unknown",e,t)};var u=()=>typeof window<"u"&&typeof document<"u";var Ge="hostRuntime",B=class{listeners=new Map;on(t,n){let r=this.listeners.get(t),s=r??new Set;return r||this.listeners.set(t,s),s.add(n),()=>{s.delete(n),s.size===0&&this.listeners.delete(t);}}emit(t,n){let r=this.listeners.get(t);if(r)for(let s of r)s(n);}},a=new B,ae=0,F=e=>(ae+=1,`${e}.${ae}`),ce=false,pe=()=>{if(!u()||ce)return;ce=true,Reflect.set(window,Ge,{receiveMessage(t){if(!t)return;let n=t.endpoint;n&&a.emit(n,t.data??t);}});};var C=e=>typeof e=="object"&&e!==null,h=(e,t)=>{if(e)for(let n of t){let r=e[n];if(typeof r=="string"&&r.length>0)return r}},Ve=(e,t)=>{if(e)for(let n of t){let r=e[n];if(typeof r=="string"&&r.length>0||typeof r=="number"&&Number.isFinite(r))return r}},E=e=>{if(!C(e))return null;let t=C(e.credentials)?e.credentials:void 0,n=C(e.user)?e.user:void 0,r=h(e,["uid","userId","id"])??h(t,["uid","userId","id"])??h(n,["uid","userId","id"]),s=h(e,["token","authToken"])??h(t,["token","authToken"]);return !r||!s?null:{uid:r,token:s}},v=e=>{if(!C(e))return null;let t=C(e.data)?e.data:e,n=Ve(t,["userId","id","uid"]);if(n===void 0)return null;let r=h(t,["username","nickname","nickName","name"]),s=h(t,["nickname","nickName","username"]);return {...t,userId:n,...r?{username:r}:{},...s?{nickname:s}:{}}};var ue="HostApp",q="hostListener";var de="processUserCredentials",le="processUserInfo",me="user.getCredentials";var R="user.credentials",j="user.info",fe="user-credentials-request",Ee="user-credentials-response";var ge="user-info-response",he={iOS:[1,6,7],Android:[1,1,8]},_e=3e3,ye=500,Re=50,Te=1500;var Je=e=>typeof e!="object"||e===null?false:typeof Reflect.get(e,"type")=="string",Ae=false,Se=()=>{!u()||Ae||(Ae=true,pe(),Reflect.set(window,de,e=>{E(e)&&a.emit(R,e);}),Reflect.set(window,le,e=>{v(e)&&a.emit(j,e);}),window.addEventListener("message",e=>{let t=e.data;if(Je(t))switch(t.type){case Ee:a.emit("iframe.credentials",t);break;case ge:a.emit("iframe.userinfo",t);break}}));};var $e=new RegExp(`${ue}\\/(\\d+\\.\\d+\\.\\d+)\\/(\\d+)\\/(iOS|Android)`),Qe=e=>{let t=e.split(".").map(n=>Number.parseInt(n,10));return [t[0]??0,t[1]??0,t[2]??0]},Ye=(e,t)=>{for(let n=0;n<3;n++){if(e[n]>t[n])return true;if(e[n]<t[n])return false}return true},Ke=e=>{let t=e.match($e);if(!t)return null;let[,n,r,s]=t;if(!n||!r||s!=="iOS"&&s!=="Android")return null;let o=Ye(Qe(n),he[s]);return {type:"native_app",platform:s,appVersion:n,buildNumber:r,meetsMinVersion:o}},Ce=()=>{if(!u())return {type:"web",meetsMinVersion:false};let e=Ke(navigator.userAgent??"");return e||(window.parent!==window?{type:"iframe",meetsMinVersion:false}:{type:"web",meetsMinVersion:false})};var Xe=(e,t,n)=>new Promise(r=>{let s=false,o=i=>{s||(s=true,c(),clearTimeout(p),r(i));},c=a.on(t,i=>{let d=n(i);d&&o(d);}),p=setTimeout(()=>o(null),ye);try{window.parent.postMessage({type:e,timestamp:Date.now()},"*");}catch{o(null);}}),we=()=>Xe(fe,"iframe.credentials",E);var Ie=e=>typeof e!="object"||e===null?false:typeof Reflect.get(e,"postMessage")=="function",G=e=>{let t=Reflect.get(window,"webkit");if(typeof t=="object"&&t!==null){let r=Reflect.get(t,"messageHandlers");if(typeof r=="object"&&r!==null){let s=Reflect.get(r,e);if(Ie(s))return s}}let n=Reflect.get(window,e);return Ie(n)?n:null},xe=(e,t={})=>{let{pollIntervalMs:n=50,timeoutMs:r=1500}=t;return new Promise(s=>{let o=Date.now(),c=()=>{let p=G(e);if(p){s(p);return}if(Date.now()-o>=r){s(null);return}setTimeout(c,n);};c();})};var We=async(e,t,n,r)=>{let s=e.platform==="Android"?await xe(q,{pollIntervalMs:Re,timeoutMs:Te}):G(q);if(!s)return null;let o=F(n);return new Promise(c=>{let p=false,i=l=>{p||(p=true,d(),_(),clearTimeout(I),c(l));},d=a.on(o,l=>{let f=r(l);f&&i(f);}),_=a.on(n,l=>{let f=r(l);f&&i(f);}),I=setTimeout(()=>i(null),_e);try{s.postMessage({command:t,parameters:JSON.stringify({timestamp:Date.now(),endpoint:o})});}catch{i(null);}})},Pe=e=>We(e,me,R,E);Se();var V=null,w=null,ze=e=>{switch(e.type){case "native_app":return e.meetsMinVersion?Pe(e):Promise.resolve(null);case "iframe":return we();case "web":return Promise.resolve(null)}};var ke=e=>{V=e;},Oe=()=>w||(w=ze(Ce()).then(e=>(e&&ke(e),e)).finally(()=>{w=null;}),w);u()&&a.on(R,e=>{let t=E(e);t&&ke(t);});var J=async()=>u()?V?V.token:(await Oe())?.token??"":"",Ne=async()=>u()?(await Oe())?.token??"":"";var Ze=e=>JSON.stringify({"sdk-version":te,...e}),ve=async(e={})=>{let t=await J(),n=new Headers;t&&n.set(z,`Bearer ${t}`),n.set(Z,Ze(e.extend));let{projectId:r}=x();if(r&&n.set(ee,r),e.contentType&&n.set("Content-Type",e.contentType),e.accept&&n.set("Accept",e.accept),e.extra)for(let[s,o]of Object.entries(e.extra))n.set(s,o);return n};var et="feed-app-runtime-sdk:auth-required",$=e=>{u()&&window.dispatchEvent(new CustomEvent(et,{detail:e}));};var tt=e=>e instanceof DOMException&&e.name==="AbortError",nt=async e=>{let t=e.headers.get("content-type")??"";try{return t.includes("application/json")?await e.json():await e.text()}catch{return null}},rt=e=>typeof e=="object"&&e!==null,st=(e,t)=>{if(!rt(e)||typeof e.success!="boolean")return e;if(e.success)return e.data;let n=typeof e.code=="number"?e.code:t;throw D(n,e)},be=async(e,t)=>{let{apiBaseUrl:n}=x(),r=`${n}${e}`,s=await ve(t),o;try{o=await fetch(r,{method:t.method??"POST",headers:s,body:t.body,signal:t.signal});}catch(p){throw tt(p)?new S:new y("Failed to reach AI backend",p)}if(o.ok)return o;let c=await nt(o);throw D(o.status,c)},Q=async(e,t={})=>{try{return await be(e,t)}catch(n){if(n instanceof g&&!t.skipAuthRetry&&!t.signal?.aborted){if(!await Ne())throw $({reason:"refresh_failed",error:n}),n;try{return await be(e,{...t,skipAuthRetry:!0})}catch(s){throw s instanceof g&&$({reason:"retry_rejected",error:s}),s}}throw n}},T=async(e,t,n={})=>{let r=await Q(e,{...n,method:"POST",contentType:"application/json",body:JSON.stringify(t)});return st(await r.json(),r.status)};var b=async(e,t,n={})=>{let r=await Q(e,{...n,method:"POST",contentType:"application/json",accept:"text/event-stream",body:JSON.stringify(t)});if(!r.body)throw new y("Streaming response has no body");return r.body},Me=async(e,t,n={})=>await(await Q(e,{...n,method:"POST",contentType:"application/json",body:JSON.stringify(t)})).blob();var M=e=>{let{signal:t,headers:n,...r}=e;return {transport:{signal:t,extra:n},payload:r}},ot=(async e=>{let{transport:t,payload:n}=M(e);if(e.stream){let r=await b(U,n,t);return re(r)}return await T(U,n,t)}),it={create:ot},at={async generate(e){let{transport:t,payload:n}=M(e);return T(K,n,t)}},ct={speech:{async create(e){let{transport:t,payload:n}=M(e);return Me(X,n,t)}}},pt={generations:{async create(e){let{transport:t,payload:n}=M(e);return T(W,n,t)}}},ut={chat:{completions:it},images:at,audio:ct,video:pt};var dt=e=>{let{signal:t,headers:n,...r}=e;return {transport:{signal:t,extra:n},payload:r}},lt=(async e=>{let{transport:t,payload:n}=dt(e);if(e.stream){let r=await b(H,n,t);return se(r)}return await T(H,n,t)}),mt={messages:{create:lt}};
|
|
3
|
+
export{S as AbortedError,m as AiError,g as AuthRequiredError,O as BadInputError,y as NetworkError,k as QuotaExceededError,P as RateLimitError,N as ServerError,mt as anthropic,qe as configureRuntime,ut as openai};
|
package/dist/react/index.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { U as UserInfo } from '../types-CLujY9ck.js';
|
|
2
|
-
import { p as ChatMessage, i as AiError } from '../errors-C0zJPCCU.js';
|
|
3
2
|
|
|
4
3
|
interface UseAuthTokenResult {
|
|
5
4
|
token: string;
|
|
@@ -26,47 +25,4 @@ interface UseUserInfoResult {
|
|
|
26
25
|
*/
|
|
27
26
|
declare const useUserInfo: () => UseUserInfoResult;
|
|
28
27
|
|
|
29
|
-
type
|
|
30
|
-
interface UseAiChatOptions {
|
|
31
|
-
/** 模型 ID(不维护别名,直接传 models.list() 返回的 id)。 */
|
|
32
|
-
model: string;
|
|
33
|
-
/** 默认 openai;anthropic 时按 Anthropic 协议路径走。 */
|
|
34
|
-
protocol?: ChatProtocol;
|
|
35
|
-
/** anthropic 协议下必填,openai 协议下可选。 */
|
|
36
|
-
maxTokens?: number;
|
|
37
|
-
/** 业务可选:每个 token 来时回调(用于打字机效果 / token 计数)。 */
|
|
38
|
-
onToken?: (delta: string) => void;
|
|
39
|
-
}
|
|
40
|
-
interface UseAiChatResult {
|
|
41
|
-
/** 完整消息历史。user 发问后立即 append,assistant 流式 token 边到边补。 */
|
|
42
|
-
messages: ChatMessage[];
|
|
43
|
-
/** 当前 assistant 正在拼接的文本(已含在 messages[-1] 里,单独暴露便于渲染 cursor)。 */
|
|
44
|
-
pending: string;
|
|
45
|
-
/** 是否有正在进行的请求。 */
|
|
46
|
-
loading: boolean;
|
|
47
|
-
/** 最近一次错误(AiError 子类 / Error / null)。 */
|
|
48
|
-
error: AiError | Error | null;
|
|
49
|
-
/** 发送一条 user 消息,触发 assistant 流式应答。 */
|
|
50
|
-
send: (content: string) => Promise<void>;
|
|
51
|
-
/** 终止当前 in-flight 请求。 */
|
|
52
|
-
stop: () => void;
|
|
53
|
-
/** 重置历史 + 错误。 */
|
|
54
|
-
reset: () => void;
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* 流式 chat 的最小 stateful hook。仅服务"和模型来回对话"的常见用例;
|
|
58
|
-
* 高级功能(工具调用、多轮 system prompt、image 输入)用 openai/anthropic
|
|
59
|
-
* 命名空间直接写。
|
|
60
|
-
*
|
|
61
|
-
* 协议差异:
|
|
62
|
-
* - openai:response 是 `chunk.choices[0].delta.content` 拼接
|
|
63
|
-
* - anthropic:response 是 `content_block_delta` 里 `text_delta.text` 拼接
|
|
64
|
-
*
|
|
65
|
-
* 错误处理:
|
|
66
|
-
* - AuthRequiredError → SDK 已强制刷新 token 并重试一次;这里只暴露最终结果,
|
|
67
|
-
* 同时会发出 auth-required 事件给容器处理
|
|
68
|
-
* - AbortedError → 用户主动 stop,error 仍会被设置,业务方按需忽略
|
|
69
|
-
*/
|
|
70
|
-
declare const useAiChat: (options: UseAiChatOptions) => UseAiChatResult;
|
|
71
|
-
|
|
72
|
-
export { type ChatProtocol, type UseAiChatOptions, type UseAiChatResult, type UseAuthTokenResult, type UseUserInfoResult, useAiChat, useAuthToken, useUserInfo };
|
|
28
|
+
export { type UseAuthTokenResult, type UseUserInfoResult, useAuthToken, useUserInfo };
|
package/dist/react/index.js
CHANGED
|
@@ -1,3 +1 @@
|
|
|
1
|
-
import {useState,useCallback,useEffect
|
|
2
|
-
`)};return r="",s=[],a};try{for(;;){let{done:a,value:p}=await t.read();if(a){let i=o();i&&(yield i);return}for(n+=St(p,!0);;){let i=_t.exec(n);if(!i)break;let f=n.slice(0,i.index);if(n=n.slice(i.index+i[0].length),f===""){let l=o();l&&(yield l);continue}if(f.startsWith(":"))continue;let h=f.indexOf(":"),R=h===-1?f:f.slice(0,h),c=h===-1?"":f.slice(h+1);c.startsWith(" ")&&(c=c.slice(1)),R==="event"?r=c:R==="data"&&s.push(c);}}}finally{t.releaseLock();}}async function*Qe(e){for await(let t of $e(e)){if(t.data==="[DONE]")return;t.data&&(yield JSON.parse(t.data));}}async function*Ke(e){for await(let t of $e(e))t.data&&(yield JSON.parse(t.data));}var wt="https://reactus-api.betteryeah.com",Ct=()=>{try{if(typeof __BTY_RUNTIME_API_BASE_URL__=="string"&&__BTY_RUNTIME_API_BASE_URL__.length>0)return __BTY_RUNTIME_API_BASE_URL__}catch{}},xt={apiBaseUrl:(Ct()??wt).replace(/\/+$/,""),projectId:""};var U=()=>xt;var E=class extends Error{status;code;body;constructor(t,n,r,s=null){super(t),this.name="AiError",this.code=n,this.status=r,this.body=s;}},C=class extends E{constructor(t="Auth required",n=null){super(t,"auth_required",401,n),this.name="AuthRequiredError";}},X=class extends E{constructor(t="Rate limit exceeded",n=null){super(t,"rate_limit",429,n),this.name="RateLimitError";}},Y=class extends E{constructor(t="Quota exceeded",n=null){super(t,"quota_exceeded",402,n),this.name="QuotaExceededError";}},W=class extends E{constructor(t,n=400,r=null){super(t,"bad_input",n,r),this.name="BadInputError";}},z=class extends E{constructor(t,n=500,r=null){super(t,"server",n,r),this.name="ServerError";}},v=class extends E{constructor(t="Network error",n){super(t,"network",-1,n),this.name="NetworkError";}},x=class extends E{constructor(t="Request aborted"){super(t,"aborted",-1,null),this.name="AbortedError";}},Xe=e=>typeof e=="object"&&e!==null,It=(e,t)=>{if(typeof e=="string")return e||t;if(!Xe(e))return t;let n=e.message;if(typeof n=="string"&&n.length>0)return n;let r=e.error;if(typeof r=="string"&&r.length>0)return r;if(Xe(r)&&typeof r.message=="string"&&r.message.length>0)return r.message;let s=e.detail;return typeof s=="string"&&s.length>0?s:t},Z=(e,t)=>{let n=It(t,`HTTP ${e}`);return e===401||e===403?new C(n,t):e===402?new Y(n,t):e===429?new X(n,t):e>=400&&e<500?new W(n,e,t):e>=500?new z(n,e,t):new E(n,"unknown",e,t)};var kt=e=>JSON.stringify({"sdk-version":Je,...e}),Ye=async(e={})=>{let n=await S(),r=new Headers;if(n&&r.set(je,`Bearer ${n}`),r.set(Ve,kt(e.extend)),e.contentType&&r.set("Content-Type",e.contentType),e.accept&&r.set("Accept",e.accept),e.extra)for(let[s,o]of Object.entries(e.extra))r.set(s,o);return r};var Pt="feed-app-runtime-sdk:auth-required",ee=e=>{g()&&window.dispatchEvent(new CustomEvent(Pt,{detail:e}));};var bt=e=>e instanceof DOMException&&e.name==="AbortError",vt=async e=>{let t=e.headers.get("content-type")??"";try{return t.includes("application/json")?await e.json():await e.text()}catch{return null}},Ot=e=>typeof e=="object"&&e!==null,Nt=(e,t)=>{if(!Ot(e)||typeof e.success!="boolean")return e;if(e.success)return e.data;let n=typeof e.code=="number"?e.code:t;throw Z(n,e)},We=async(e,t)=>{let{apiBaseUrl:n}=U(),r=`${n}${e}`,s=await Ye(t),o;try{o=await fetch(r,{method:t.method??"POST",headers:s,body:t.body,signal:t.signal});}catch(p){throw bt(p)?new x:new v("Failed to reach AI backend",p)}if(o.ok)return o;let a=await vt(o);throw Z(o.status,a)},te=async(e,t={})=>{try{return await We(e,t)}catch(n){if(n instanceof C&&!t.skipAuthRetry&&!t.signal?.aborted){if(!await Me())throw ee({reason:"refresh_failed",error:n}),n;try{return await We(e,{...t,skipAuthRetry:!0})}catch(s){throw s instanceof C&&ee({reason:"retry_rejected",error:s}),s}}throw n}},I=async(e,t,n={})=>{let r=await te(e,{...n,method:"POST",contentType:"application/json",body:JSON.stringify(t)});return Nt(await r.json(),r.status)};var M=async(e,t,n={})=>{let r=await te(e,{...n,method:"POST",contentType:"application/json",accept:"text/event-stream",body:JSON.stringify(t)});if(!r.body)throw new v("Streaming response has no body");return r.body},ze=async(e,t,n={})=>await(await te(e,{...n,method:"POST",contentType:"application/json",body:JSON.stringify(t)})).blob();var Ut=e=>{let{signal:t,headers:n,...r}=e;return {transport:{signal:t,extra:n},payload:r}},Mt=(async e=>{let{transport:t,payload:n}=Ut(e);if(e.stream){let r=await M(K,n,t);return Ke(r)}return await I(K,n,t)}),Ze={messages:{create:Mt}};var H=e=>{let{signal:t,headers:n,...r}=e;return {transport:{signal:t,extra:n},payload:r}},Ht=(async e=>{let{transport:t,payload:n}=H(e);if(e.stream){let r=await M(Q,n,t);return Qe(r)}return await I(Q,n,t)}),Lt={create:Ht},Dt={async generate(e){let{transport:t,payload:n}=H(e);return I(Fe,n,t)}},Ft={speech:{async create(e){let{transport:t,payload:n}=H(e);return ze(Be,n,t)}}},Bt={generations:{async create(e){let{transport:t,payload:n}=H(e);return I(qe,n,t)}}},et={chat:{completions:Lt},images:Dt,audio:Ft,video:Bt};var jt=e=>{let{model:t,protocol:n="openai",maxTokens:r=1024,onToken:s}=e,[o,a]=useState([]),[p,i]=useState(""),[f,h]=useState(false),[R,c]=useState(null),l=useRef(null),re=useRef(s);re.current=s,useEffect(()=>()=>l.current?.abort(),[]);let nt=useCallback(()=>l.current?.abort(),[]),rt=useCallback(()=>{l.current?.abort(),a([]),i(""),c(null),h(false);},[]),st=useCallback(async se=>{if(!se)return;c(null),i(""),h(true);let D={role:"user",content:se},ot={role:"assistant",content:""};a(u=>[...u,D,ot]);let F=new AbortController;l.current?.abort(),l.current=F;let B="",oe=u=>{u&&(B+=u,i(B),a(k=>{let d=k.slice();return d[d.length-1]={role:"assistant",content:B},d}),re.current?.(u));};try{if(n==="openai"){let u=await et.chat.completions.create({model:t,messages:[...o,D],stream:!0,signal:F.signal});for await(let k of u){let d=k.choices?.[0]?.delta?.content;typeof d=="string"&&oe(d);}}else {let u=[...o,D].map(d=>({role:d.role==="assistant"?"assistant":"user",content:typeof d.content=="string"?d.content:""})),k=await Ze.messages.create({model:t,messages:u,max_tokens:r,stream:!0,signal:F.signal});for await(let d of k)d.type==="content_block_delta"&&d.delta.type==="text_delta"&&oe(d.delta.text);}}catch(u){u instanceof x||u instanceof E||u instanceof Error?c(u):c(new Error(String(u)));}finally{h(false),i("");}},[r,o,t,n]);return {messages:o,pending:p,loading:f,error:R,send:st,stop:nt,reset:rt}};
|
|
3
|
-
export{jt as useAiChat,ht as useAuthToken,Rt as useUserInfo};
|
|
1
|
+
import {useState,useCallback,useEffect}from'react';var l=()=>typeof window<"u"&&typeof document<"u";var ue="hostRuntime",N=class{listeners=new Map;on(t,r){let n=this.listeners.get(t),s=n??new Set;return n||this.listeners.set(t,s),s.add(r),()=>{s.delete(r),s.size===0&&this.listeners.delete(t);}}emit(t,r){let n=this.listeners.get(t);if(n)for(let s of n)s(r);}},i=new N,C=0,U=e=>(C+=1,`${e}.${C}`),M=false,h=()=>{if(!l()||M)return;M=true,Reflect.set(window,ue,{receiveMessage(t){if(!t)return;let r=t.endpoint;r&&i.emit(r,t.data??t);}});};var _=e=>typeof e=="object"&&e!==null,p=(e,t)=>{if(e)for(let r of t){let n=e[r];if(typeof n=="string"&&n.length>0)return n}},le=(e,t)=>{if(e)for(let r of t){let n=e[r];if(typeof n=="string"&&n.length>0||typeof n=="number"&&Number.isFinite(n))return n}},f=e=>{if(!_(e))return null;let t=_(e.credentials)?e.credentials:void 0,r=_(e.user)?e.user:void 0,n=p(e,["uid","userId","id"])??p(t,["uid","userId","id"])??p(r,["uid","userId","id"]),s=p(e,["token","authToken"])??p(t,["token","authToken"]);return !n||!s?null:{uid:n,token:s}},m=e=>{if(!_(e))return null;let t=_(e.data)?e.data:e,r=le(t,["userId","id","uid"]);if(r===void 0)return null;let n=p(t,["username","nickname","nickName","name"]),s=p(t,["nickname","nickName","username"]);return {...t,userId:r,...n?{username:n}:{},...s?{nickname:s}:{}}};var O="HostApp",k="hostListener";var x="processUserCredentials",P="processUserInfo",L="user.getCredentials",b="user.getUserInfo",d="user.credentials",g="user.info",F="user-credentials-request",H="user-credentials-response",D="user-info-request",q="user-info-response",B={iOS:[1,6,7],Android:[1,1,8]},V=3e3,j=500,G=50,Q=1500;var ae=e=>typeof e!="object"||e===null?false:typeof Reflect.get(e,"type")=="string",$=false,K=()=>{!l()||$||($=true,h(),Reflect.set(window,x,e=>{f(e)&&i.emit(d,e);}),Reflect.set(window,P,e=>{m(e)&&i.emit(g,e);}),window.addEventListener("message",e=>{let t=e.data;if(ae(t))switch(t.type){case H:i.emit("iframe.credentials",t);break;case q:i.emit("iframe.userinfo",t);break}}));};var fe=new RegExp(`${O}\\/(\\d+\\.\\d+\\.\\d+)\\/(\\d+)\\/(iOS|Android)`),ce=e=>{let t=e.split(".").map(r=>Number.parseInt(r,10));return [t[0]??0,t[1]??0,t[2]??0]},pe=(e,t)=>{for(let r=0;r<3;r++){if(e[r]>t[r])return true;if(e[r]<t[r])return false}return true},me=e=>{let t=e.match(fe);if(!t)return null;let[,r,n,s]=t;if(!r||!n||s!=="iOS"&&s!=="Android")return null;let o=pe(ce(r),B[s]);return {type:"native_app",platform:s,appVersion:r,buildNumber:n,meetsMinVersion:o}},w=()=>{if(!l())return {type:"web",meetsMinVersion:false};let e=me(navigator.userAgent??"");return e||(window.parent!==window?{type:"iframe",meetsMinVersion:false}:{type:"web",meetsMinVersion:false})};var z=(e,t,r)=>new Promise(n=>{let s=false,o=a=>{s||(s=true,u(),clearTimeout(c),n(a));},u=i.on(t,a=>{let S=r(a);S&&o(S);}),c=setTimeout(()=>o(null),j);try{window.parent.postMessage({type:e,timestamp:Date.now()},"*");}catch{o(null);}}),J=()=>z(F,"iframe.credentials",f),X=()=>z(D,"iframe.userinfo",m);var W=e=>typeof e!="object"||e===null?false:typeof Reflect.get(e,"postMessage")=="function",v=e=>{let t=Reflect.get(window,"webkit");if(typeof t=="object"&&t!==null){let n=Reflect.get(t,"messageHandlers");if(typeof n=="object"&&n!==null){let s=Reflect.get(n,e);if(W(s))return s}}let r=Reflect.get(window,e);return W(r)?r:null},Y=(e,t={})=>{let{pollIntervalMs:r=50,timeoutMs:n=1500}=t;return new Promise(s=>{let o=Date.now(),u=()=>{let c=v(e);if(c){s(c);return}if(Date.now()-o>=n){s(null);return}setTimeout(u,r);};u();})};var Z=async(e,t,r,n)=>{let s=e.platform==="Android"?await Y(k,{pollIntervalMs:G,timeoutMs:Q}):v(k);if(!s)return null;let o=U(r);return new Promise(u=>{let c=false,a=E=>{c||(c=true,S(),oe(),clearTimeout(ie),u(E));},S=i.on(o,E=>{let I=n(E);I&&a(I);}),oe=i.on(r,E=>{let I=n(E);I&&a(I);}),ie=setTimeout(()=>a(null),V);try{s.postMessage({command:t,parameters:JSON.stringify({timestamp:Date.now(),endpoint:o})});}catch{a(null);}})},ee=e=>Z(e,L,d,f),te=e=>Z(e,b,g,m);K();var y=null,T=null,de=e=>{switch(e.type){case "native_app":return e.meetsMinVersion?ee(e):Promise.resolve(null);case "iframe":return J();case "web":return Promise.resolve(null)}},Ee=e=>{switch(e.type){case "native_app":return e.meetsMinVersion?te(e):Promise.resolve(null);case "iframe":return X();case "web":return Promise.resolve(null)}},ne=e=>{y=e;},Ie=()=>T||(T=de(w()).then(e=>(e&&ne(e),e)).finally(()=>{T=null;}),T);l()&&i.on(d,e=>{let t=f(e);t&&ne(t);});var R=async()=>l()?y?y.token:(await Ie())?.token??"":"";var A=async()=>l()?Ee(w()):null;var Se=()=>{let[e,t]=useState(""),[r,n]=useState(true),s=useCallback(()=>{n(true),R().then(o=>{t(o),n(false);});},[]);return useEffect(()=>{let o=true;return R().then(u=>{o&&(t(u),n(false));}),()=>{o=false;}},[]),{token:e,loading:r,refetch:s}};var Ae=()=>{let[e,t]=useState(null),[r,n]=useState(true),s=useCallback(()=>{n(true),A().then(o=>{t(o),n(false);});},[]);return useEffect(()=>{let o=true;return A().then(u=>{o&&(t(u),n(false));}),()=>{o=false;}},[]),{user:e,loading:r,refetch:s}};export{Se as useAuthToken,Ae as useUserInfo};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bty/feed_app-runtime-sdk",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.7",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"browser": true,
|
|
6
6
|
"description": "Runtime SDK for feed-app template: auth / AI capabilities, multi-environment bridge (native App / iframe / web).",
|
|
@@ -20,7 +20,8 @@
|
|
|
20
20
|
"./react": {
|
|
21
21
|
"types": "./dist/react/index.d.ts",
|
|
22
22
|
"import": "./dist/react/index.js"
|
|
23
|
-
}
|
|
23
|
+
},
|
|
24
|
+
"./package.json": "./package.json"
|
|
24
25
|
},
|
|
25
26
|
"publishConfig": {
|
|
26
27
|
"access": "public",
|
|
@@ -1,295 +0,0 @@
|
|
|
1
|
-
interface ApiRequestOptions {
|
|
2
|
-
/** AbortSignal — propagated through fetch into the upstream stream. */
|
|
3
|
-
signal?: AbortSignal;
|
|
4
|
-
/** Extra HTTP headers merged on top of SDK-injected ones. */
|
|
5
|
-
headers?: Record<string, string>;
|
|
6
|
-
}
|
|
7
|
-
interface ChatMessage {
|
|
8
|
-
role: "system" | "user" | "assistant" | "tool";
|
|
9
|
-
content: string | ChatContentPart[];
|
|
10
|
-
name?: string;
|
|
11
|
-
tool_call_id?: string;
|
|
12
|
-
tool_calls?: ChatToolCall[];
|
|
13
|
-
[key: string]: unknown;
|
|
14
|
-
}
|
|
15
|
-
interface ChatContentPart {
|
|
16
|
-
type: "text" | "image_url" | "input_audio";
|
|
17
|
-
text?: string;
|
|
18
|
-
image_url?: {
|
|
19
|
-
url: string;
|
|
20
|
-
detail?: "low" | "high" | "auto";
|
|
21
|
-
};
|
|
22
|
-
input_audio?: {
|
|
23
|
-
data: string;
|
|
24
|
-
format: "wav" | "mp3";
|
|
25
|
-
};
|
|
26
|
-
[key: string]: unknown;
|
|
27
|
-
}
|
|
28
|
-
interface ChatToolCall {
|
|
29
|
-
id: string;
|
|
30
|
-
type: "function";
|
|
31
|
-
function: {
|
|
32
|
-
name: string;
|
|
33
|
-
arguments: string;
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
interface ChatTool {
|
|
37
|
-
type: "function";
|
|
38
|
-
function: {
|
|
39
|
-
name: string;
|
|
40
|
-
description?: string;
|
|
41
|
-
parameters?: Record<string, unknown>;
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
interface ChatCompletionCreateParams extends ApiRequestOptions {
|
|
45
|
-
model: string;
|
|
46
|
-
messages: ChatMessage[];
|
|
47
|
-
stream?: boolean;
|
|
48
|
-
temperature?: number;
|
|
49
|
-
top_p?: number;
|
|
50
|
-
max_tokens?: number;
|
|
51
|
-
tools?: ChatTool[];
|
|
52
|
-
tool_choice?: "auto" | "none" | "required" | {
|
|
53
|
-
type: string;
|
|
54
|
-
function: {
|
|
55
|
-
name: string;
|
|
56
|
-
};
|
|
57
|
-
};
|
|
58
|
-
response_format?: {
|
|
59
|
-
type: "text" | "json_object" | "json_schema";
|
|
60
|
-
[key: string]: unknown;
|
|
61
|
-
};
|
|
62
|
-
[key: string]: unknown;
|
|
63
|
-
}
|
|
64
|
-
interface ChatCompletion {
|
|
65
|
-
id: string;
|
|
66
|
-
object: "chat.completion";
|
|
67
|
-
created: number;
|
|
68
|
-
model: string;
|
|
69
|
-
choices: {
|
|
70
|
-
index: number;
|
|
71
|
-
message: {
|
|
72
|
-
role: "assistant";
|
|
73
|
-
content: string | null;
|
|
74
|
-
tool_calls?: ChatToolCall[];
|
|
75
|
-
};
|
|
76
|
-
finish_reason: string | null;
|
|
77
|
-
}[];
|
|
78
|
-
usage?: {
|
|
79
|
-
prompt_tokens: number;
|
|
80
|
-
completion_tokens: number;
|
|
81
|
-
total_tokens: number;
|
|
82
|
-
};
|
|
83
|
-
[key: string]: unknown;
|
|
84
|
-
}
|
|
85
|
-
interface ChatCompletionChunk {
|
|
86
|
-
id: string;
|
|
87
|
-
object: "chat.completion.chunk";
|
|
88
|
-
created: number;
|
|
89
|
-
model: string;
|
|
90
|
-
choices: {
|
|
91
|
-
index: number;
|
|
92
|
-
delta: {
|
|
93
|
-
role?: "assistant";
|
|
94
|
-
content?: string;
|
|
95
|
-
tool_calls?: Partial<ChatToolCall>[];
|
|
96
|
-
};
|
|
97
|
-
finish_reason: string | null;
|
|
98
|
-
}[];
|
|
99
|
-
[key: string]: unknown;
|
|
100
|
-
}
|
|
101
|
-
interface ImageGenerateParams extends ApiRequestOptions {
|
|
102
|
-
prompt: string;
|
|
103
|
-
model?: string;
|
|
104
|
-
n?: number;
|
|
105
|
-
size?: string;
|
|
106
|
-
quality?: "standard" | "hd";
|
|
107
|
-
style?: "vivid" | "natural";
|
|
108
|
-
response_format?: "url" | "b64_json";
|
|
109
|
-
[key: string]: unknown;
|
|
110
|
-
}
|
|
111
|
-
interface ImageGenerateResponse {
|
|
112
|
-
created: number;
|
|
113
|
-
data: {
|
|
114
|
-
url?: string;
|
|
115
|
-
b64_json?: string;
|
|
116
|
-
revised_prompt?: string;
|
|
117
|
-
}[];
|
|
118
|
-
}
|
|
119
|
-
interface AudioSpeechCreateParams extends ApiRequestOptions {
|
|
120
|
-
model: string;
|
|
121
|
-
input: string;
|
|
122
|
-
voice: string;
|
|
123
|
-
response_format?: "mp3" | "opus" | "aac" | "flac" | "wav" | "pcm";
|
|
124
|
-
speed?: number;
|
|
125
|
-
[key: string]: unknown;
|
|
126
|
-
}
|
|
127
|
-
interface VideoGenerateParams extends ApiRequestOptions {
|
|
128
|
-
prompt: string;
|
|
129
|
-
model?: string;
|
|
130
|
-
duration?: number;
|
|
131
|
-
size?: string;
|
|
132
|
-
[key: string]: unknown;
|
|
133
|
-
}
|
|
134
|
-
interface VideoGenerateResponse {
|
|
135
|
-
created: number;
|
|
136
|
-
data: {
|
|
137
|
-
url?: string;
|
|
138
|
-
b64_json?: string;
|
|
139
|
-
}[];
|
|
140
|
-
[key: string]: unknown;
|
|
141
|
-
}
|
|
142
|
-
interface AnthropicMessage {
|
|
143
|
-
role: "user" | "assistant";
|
|
144
|
-
content: string | AnthropicContentBlock[];
|
|
145
|
-
}
|
|
146
|
-
type AnthropicContentBlock = {
|
|
147
|
-
type: "text";
|
|
148
|
-
text: string;
|
|
149
|
-
} | {
|
|
150
|
-
type: "image";
|
|
151
|
-
source: {
|
|
152
|
-
type: "base64";
|
|
153
|
-
media_type: "image/jpeg" | "image/png" | "image/gif" | "image/webp";
|
|
154
|
-
data: string;
|
|
155
|
-
};
|
|
156
|
-
} | {
|
|
157
|
-
type: "tool_use";
|
|
158
|
-
id: string;
|
|
159
|
-
name: string;
|
|
160
|
-
input: Record<string, unknown>;
|
|
161
|
-
} | {
|
|
162
|
-
type: "tool_result";
|
|
163
|
-
tool_use_id: string;
|
|
164
|
-
content: string | AnthropicContentBlock[];
|
|
165
|
-
};
|
|
166
|
-
interface AnthropicTool {
|
|
167
|
-
name: string;
|
|
168
|
-
description?: string;
|
|
169
|
-
input_schema: Record<string, unknown>;
|
|
170
|
-
}
|
|
171
|
-
interface MessagesCreateParams extends ApiRequestOptions {
|
|
172
|
-
model: string;
|
|
173
|
-
messages: AnthropicMessage[];
|
|
174
|
-
max_tokens: number;
|
|
175
|
-
system?: string | AnthropicContentBlock[];
|
|
176
|
-
stream?: boolean;
|
|
177
|
-
temperature?: number;
|
|
178
|
-
top_p?: number;
|
|
179
|
-
top_k?: number;
|
|
180
|
-
tools?: AnthropicTool[];
|
|
181
|
-
tool_choice?: {
|
|
182
|
-
type: "auto" | "any" | "tool";
|
|
183
|
-
name?: string;
|
|
184
|
-
};
|
|
185
|
-
stop_sequences?: string[];
|
|
186
|
-
[key: string]: unknown;
|
|
187
|
-
}
|
|
188
|
-
interface AnthropicMessageResponse {
|
|
189
|
-
id: string;
|
|
190
|
-
type: "message";
|
|
191
|
-
role: "assistant";
|
|
192
|
-
model: string;
|
|
193
|
-
content: AnthropicContentBlock[];
|
|
194
|
-
stop_reason: string | null;
|
|
195
|
-
stop_sequence: string | null;
|
|
196
|
-
usage: {
|
|
197
|
-
input_tokens: number;
|
|
198
|
-
output_tokens: number;
|
|
199
|
-
};
|
|
200
|
-
[key: string]: unknown;
|
|
201
|
-
}
|
|
202
|
-
type AnthropicStreamEvent = {
|
|
203
|
-
type: "message_start";
|
|
204
|
-
message: AnthropicMessageResponse;
|
|
205
|
-
} | {
|
|
206
|
-
type: "content_block_start";
|
|
207
|
-
index: number;
|
|
208
|
-
content_block: AnthropicContentBlock;
|
|
209
|
-
} | {
|
|
210
|
-
type: "content_block_delta";
|
|
211
|
-
index: number;
|
|
212
|
-
delta: {
|
|
213
|
-
type: "text_delta";
|
|
214
|
-
text: string;
|
|
215
|
-
} | {
|
|
216
|
-
type: "input_json_delta";
|
|
217
|
-
partial_json: string;
|
|
218
|
-
};
|
|
219
|
-
} | {
|
|
220
|
-
type: "content_block_stop";
|
|
221
|
-
index: number;
|
|
222
|
-
} | {
|
|
223
|
-
type: "message_delta";
|
|
224
|
-
delta: {
|
|
225
|
-
stop_reason: string | null;
|
|
226
|
-
stop_sequence: string | null;
|
|
227
|
-
};
|
|
228
|
-
usage: {
|
|
229
|
-
output_tokens: number;
|
|
230
|
-
};
|
|
231
|
-
} | {
|
|
232
|
-
type: "message_stop";
|
|
233
|
-
} | {
|
|
234
|
-
type: "ping";
|
|
235
|
-
} | {
|
|
236
|
-
type: "error";
|
|
237
|
-
error: {
|
|
238
|
-
type: string;
|
|
239
|
-
message: string;
|
|
240
|
-
};
|
|
241
|
-
};
|
|
242
|
-
interface ModelInfo {
|
|
243
|
-
id: string;
|
|
244
|
-
/** Which protocol this model is served via. */
|
|
245
|
-
protocol: "openai" | "anthropic";
|
|
246
|
-
/** Capability flags — drives CodingAgent's choice. */
|
|
247
|
-
capabilities: {
|
|
248
|
-
chat?: boolean;
|
|
249
|
-
images?: boolean;
|
|
250
|
-
audio?: boolean;
|
|
251
|
-
video?: boolean;
|
|
252
|
-
vision?: boolean;
|
|
253
|
-
tools?: boolean;
|
|
254
|
-
};
|
|
255
|
-
/** Free-form descriptive label, safe to show in UI. */
|
|
256
|
-
display_name?: string;
|
|
257
|
-
/** Approximate max context tokens — for UX hints. */
|
|
258
|
-
context_window?: number;
|
|
259
|
-
[key: string]: unknown;
|
|
260
|
-
}
|
|
261
|
-
interface ModelsListResponse {
|
|
262
|
-
object: "list";
|
|
263
|
-
data: ModelInfo[];
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
type AiErrorCode = "auth_required" | "rate_limit" | "quota_exceeded" | "bad_input" | "server" | "network" | "aborted" | "unknown";
|
|
267
|
-
declare class AiError extends Error {
|
|
268
|
-
readonly status: number;
|
|
269
|
-
readonly code: AiErrorCode;
|
|
270
|
-
readonly body: unknown;
|
|
271
|
-
constructor(message: string, code: AiErrorCode, status: number, body?: unknown);
|
|
272
|
-
}
|
|
273
|
-
declare class AuthRequiredError extends AiError {
|
|
274
|
-
constructor(message?: string, body?: unknown);
|
|
275
|
-
}
|
|
276
|
-
declare class RateLimitError extends AiError {
|
|
277
|
-
constructor(message?: string, body?: unknown);
|
|
278
|
-
}
|
|
279
|
-
declare class QuotaExceededError extends AiError {
|
|
280
|
-
constructor(message?: string, body?: unknown);
|
|
281
|
-
}
|
|
282
|
-
declare class BadInputError extends AiError {
|
|
283
|
-
constructor(message: string, status?: number, body?: unknown);
|
|
284
|
-
}
|
|
285
|
-
declare class ServerError extends AiError {
|
|
286
|
-
constructor(message: string, status?: number, body?: unknown);
|
|
287
|
-
}
|
|
288
|
-
declare class NetworkError extends AiError {
|
|
289
|
-
constructor(message?: string, cause?: unknown);
|
|
290
|
-
}
|
|
291
|
-
declare class AbortedError extends AiError {
|
|
292
|
-
constructor(message?: string);
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
export { type AudioSpeechCreateParams as A, BadInputError as B, type ChatCompletionCreateParams as C, type ImageGenerateParams as I, type MessagesCreateParams as M, NetworkError as N, QuotaExceededError as Q, RateLimitError as R, ServerError as S, type VideoGenerateParams as V, type ChatCompletionChunk as a, type ChatCompletion as b, type ImageGenerateResponse as c, type VideoGenerateResponse as d, type AnthropicStreamEvent as e, type AnthropicMessageResponse as f, type ModelInfo as g, AbortedError as h, AiError as i, type AiErrorCode as j, type AnthropicContentBlock as k, type AnthropicMessage as l, type AnthropicTool as m, AuthRequiredError as n, type ChatContentPart as o, type ChatMessage as p, type ChatTool as q, type ChatToolCall as r, type ModelsListResponse as s };
|