@ateam-ai-mobile/core 0.1.3 → 0.1.5
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/dist/index.d.mts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +88 -60
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +87 -60
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
- package/src/api/tenants.ts +16 -3
- package/src/chat/store.ts +93 -73
- package/src/index.ts +1 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ateam-ai-mobile/core",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "Headless ADAS SDK core
|
|
3
|
+
"version": "0.1.5",
|
|
4
|
+
"description": "Headless ADAS SDK core — auth bridge, API client, chat/job streaming, MCP calls, theme tokens. No UI, no Expo dependencies.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"scripts": {
|
|
@@ -24,4 +24,4 @@
|
|
|
24
24
|
"publishConfig": {
|
|
25
25
|
"access": "public"
|
|
26
26
|
}
|
|
27
|
-
}
|
|
27
|
+
}
|
package/src/api/tenants.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { apiFetch } from './client';
|
|
2
1
|
import { getConsumerAuthApiUrl, getToken, getConfig, type AdasSession } from '../config';
|
|
3
2
|
import { useChatStore, closeChatStream } from '../chat/store';
|
|
4
3
|
|
|
@@ -17,8 +16,22 @@ export interface TenantMembership {
|
|
|
17
16
|
* leaks the full tenant list. Returns [] when signed out or unknown.
|
|
18
17
|
*/
|
|
19
18
|
export async function listMyTenants(): Promise<TenantMembership[]> {
|
|
20
|
-
const
|
|
21
|
-
|
|
19
|
+
const token = getToken();
|
|
20
|
+
if (!token) return [];
|
|
21
|
+
try {
|
|
22
|
+
const res = await fetch(`${getConsumerAuthApiUrl()}/platform/consumer/my-tenants`, {
|
|
23
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
24
|
+
});
|
|
25
|
+
const data = await res.json().catch(() => null);
|
|
26
|
+
if (!res.ok || !data?.ok || !Array.isArray(data.tenants)) return [];
|
|
27
|
+
return data.tenants.map((t: any) => ({
|
|
28
|
+
id: t.id,
|
|
29
|
+
name: t.name || t.id,
|
|
30
|
+
role: t.role ?? null,
|
|
31
|
+
}));
|
|
32
|
+
} catch {
|
|
33
|
+
return [];
|
|
34
|
+
}
|
|
22
35
|
}
|
|
23
36
|
|
|
24
37
|
/**
|
package/src/chat/store.ts
CHANGED
|
@@ -353,85 +353,105 @@ export const useChatStore = create<ChatState>((set, get) => ({
|
|
|
353
353
|
|
|
354
354
|
let firstRunning: Message | undefined = keptPlaceholders.find(m => m.jobProgress?.status === 'running');
|
|
355
355
|
|
|
356
|
-
// Cold-start / post-refresh reattach:
|
|
357
|
-
// restart.
|
|
358
|
-
//
|
|
359
|
-
//
|
|
356
|
+
// Cold-start / post-refresh reattach: WS subscriptions die on app
|
|
357
|
+
// restart. Fetch ALL active chains for this actor (chain-native SlimChain
|
|
358
|
+
// API) and reattach EACH — multiple concurrent chains must all come back
|
|
359
|
+
// in progress, not just the most-recently-updated one. Falls back to the
|
|
360
|
+
// legacy single-chain /api/chain/current on older backends.
|
|
360
361
|
try {
|
|
361
|
-
|
|
362
|
+
let activeChains: any[] = [];
|
|
363
|
+
const chainsRes = await fetch(`${getCoreApiUrl()}/api/chains/active`, {
|
|
362
364
|
headers: coreHeaders(),
|
|
363
365
|
});
|
|
364
|
-
if (
|
|
365
|
-
const
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
// Re-open the live subscription.
|
|
431
|
-
streamJob(chainId, getTenant(), getToken());
|
|
366
|
+
if (chainsRes.ok) {
|
|
367
|
+
const body = await chainsRes.json();
|
|
368
|
+
activeChains = Array.isArray(body?.chains) ? body.chains : [];
|
|
369
|
+
} else {
|
|
370
|
+
// Legacy backend without the plural endpoint — single most-recent chain.
|
|
371
|
+
const legacy = await fetch(`${getCoreApiUrl()}/api/chain/current`, {
|
|
372
|
+
headers: coreHeaders(),
|
|
373
|
+
});
|
|
374
|
+
if (legacy.ok) {
|
|
375
|
+
const lb = await legacy.json();
|
|
376
|
+
if (lb?.data?.id) activeChains = [lb.data];
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
for (const slim of activeChains) {
|
|
381
|
+
if (!slim?.id) continue;
|
|
382
|
+
const chainId = String(slim.id);
|
|
383
|
+
const alreadyTracked = finalMessages.some(m =>
|
|
384
|
+
m.role === 'assistant' && m.jobProgress?.jobId === chainId
|
|
385
|
+
);
|
|
386
|
+
if (alreadyTracked) continue;
|
|
387
|
+
|
|
388
|
+
// Chain-native status: prefer the whole-chain aggregate (chainStatus)
|
|
389
|
+
// over the active job's per-job status, so e.g. a chain still running
|
|
390
|
+
// across a handoff isn't shown as "done". A pending question still
|
|
391
|
+
// overrides to "paused" inside snapshotToProgress.
|
|
392
|
+
const progress = snapshotToProgress(
|
|
393
|
+
{ ...slim, status: slim.chainStatus || slim.status },
|
|
394
|
+
chainId,
|
|
395
|
+
);
|
|
396
|
+
const chainCreatedAt = typeof slim.createdAt === 'number'
|
|
397
|
+
? slim.createdAt
|
|
398
|
+
: (typeof slim.lastUpdate === 'number' ? slim.lastUpdate : Date.now());
|
|
399
|
+
const chainLastUpdate = typeof slim.lastUpdate === 'number' ? slim.lastUpdate : chainCreatedAt;
|
|
400
|
+
const jobProgress = {
|
|
401
|
+
jobId: chainId,
|
|
402
|
+
actorId: extractActorId(slim),
|
|
403
|
+
status: 'running',
|
|
404
|
+
chainStartedAt: chainCreatedAt,
|
|
405
|
+
...progress,
|
|
406
|
+
} as JobProgress;
|
|
407
|
+
|
|
408
|
+
// Synthesize the user bubble if a hard refresh wiped the optimistic
|
|
409
|
+
// one and the chain hasn't persisted its turn yet.
|
|
410
|
+
const goal = typeof slim.goal === 'string' ? slim.goal : '';
|
|
411
|
+
const userExists = finalMessages.some(m =>
|
|
412
|
+
m.role === 'user' && (m.chainId === chainId || (goal && m.content === goal))
|
|
413
|
+
);
|
|
414
|
+
if (goal && !userExists) {
|
|
415
|
+
finalMessages.push({
|
|
416
|
+
id: `user-${chainId}`,
|
|
417
|
+
role: 'user',
|
|
418
|
+
content: goal,
|
|
419
|
+
timestamp: new Date(chainCreatedAt),
|
|
420
|
+
chainId,
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// Assistant side: attach to matching persisted turn if one exists;
|
|
425
|
+
// otherwise push a placeholder bubble.
|
|
426
|
+
let matchIdx = -1;
|
|
427
|
+
for (let i = finalMessages.length - 1; i >= 0; i--) {
|
|
428
|
+
const m = finalMessages[i];
|
|
429
|
+
if (m.role === 'assistant' && m.chainId === chainId) {
|
|
430
|
+
matchIdx = i;
|
|
431
|
+
break;
|
|
432
432
|
}
|
|
433
433
|
}
|
|
434
|
+
if (matchIdx >= 0) {
|
|
435
|
+
finalMessages[matchIdx] = { ...finalMessages[matchIdx], jobProgress };
|
|
436
|
+
if (jobProgress.status === 'running' && !firstRunning) firstRunning = finalMessages[matchIdx];
|
|
437
|
+
} else {
|
|
438
|
+
const reattachBubble: Message = {
|
|
439
|
+
id: `job-${chainId}`,
|
|
440
|
+
role: 'assistant',
|
|
441
|
+
content: 'Working on it...',
|
|
442
|
+
timestamp: new Date(chainLastUpdate),
|
|
443
|
+
jobProgress,
|
|
444
|
+
chainId,
|
|
445
|
+
};
|
|
446
|
+
finalMessages.push(reattachBubble);
|
|
447
|
+
if (jobProgress.status === 'running' && !firstRunning) firstRunning = reattachBubble;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
// Re-open the live subscription for this chain.
|
|
451
|
+
streamJob(chainId, getTenant(), getToken());
|
|
434
452
|
}
|
|
453
|
+
|
|
454
|
+
finalMessages.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
|
|
435
455
|
} catch {}
|
|
436
456
|
|
|
437
457
|
set({
|