@ateam-ai-mobile/core 0.1.4 → 0.1.6
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 +22 -1
- package/dist/index.d.ts +22 -1
- package/dist/index.js +44 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +42 -0
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/chat/store.ts +9 -0
- package/src/index.ts +2 -0
- package/src/session.ts +62 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ateam-ai-mobile/core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
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",
|
package/src/chat/store.ts
CHANGED
|
@@ -182,7 +182,16 @@ function renderTableShape(content: any): string | null {
|
|
|
182
182
|
*/
|
|
183
183
|
export function blocksToText(blocks?: Array<{ kind: string; content: any }>): string {
|
|
184
184
|
if (!blocks || blocks.length === 0) return '';
|
|
185
|
+
// Mirror the web renderer: when a human-readable text/markdown block exists in
|
|
186
|
+
// the same turn, drop internal-state json/code blocks (planning state,
|
|
187
|
+
// askUser payloads) — otherwise they render as a raw ```json blob AFTER the
|
|
188
|
+
// real answer. Standalone json/code (no text block, e.g. a table-only turn)
|
|
189
|
+
// still renders as before.
|
|
190
|
+
const hasTextBlock = blocks.some(
|
|
191
|
+
b => b.kind === 'text' || b.kind === 'markdown' || b.kind === 'description',
|
|
192
|
+
);
|
|
185
193
|
return blocks.map(b => {
|
|
194
|
+
if ((b.kind === 'json' || b.kind === 'code') && hasTextBlock) return '';
|
|
186
195
|
if (b.kind === 'text' || b.kind === 'markdown' || b.kind === 'description') {
|
|
187
196
|
return typeof b.content === 'string' ? b.content : '';
|
|
188
197
|
}
|
package/src/index.ts
CHANGED
|
@@ -44,6 +44,8 @@ export {
|
|
|
44
44
|
} from './api/mcp';
|
|
45
45
|
|
|
46
46
|
// Tenant memberships
|
|
47
|
+
export { getSession, isDevHost } from './session';
|
|
48
|
+
export type { Session, SessionEnv } from './session';
|
|
47
49
|
export { listMyTenants, switchTenant } from './api/tenants';
|
|
48
50
|
export type { TenantMembership } from './api/tenants';
|
|
49
51
|
|
package/src/session.ts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// packages/core/src/session.ts
|
|
2
|
+
//
|
|
3
|
+
// THE single answer to "where am I / what am I talking to / who am I", derived
|
|
4
|
+
// from the SDK config the REQUESTS themselves use — getTenant / getConsumerAuthApiUrl
|
|
5
|
+
// / getCoreApiUrl / getUser. Because the label reads from the same place the
|
|
6
|
+
// request reads, they cannot disagree. Host-agnostic: any host that calls
|
|
7
|
+
// initAdas() gets a correct session with no parallel copy to drift.
|
|
8
|
+
//
|
|
9
|
+
// Rule: DERIVE, NEVER STORE — see Docs/DERIVE_NEVER_STORE.md. This lives in the
|
|
10
|
+
// SDK (not a host app) so iOS/Android/RN hosts share one derivation; the host's
|
|
11
|
+
// React hook (e.g. useSession) is a thin wrapper that just re-renders on change.
|
|
12
|
+
|
|
13
|
+
import { getTenant, getConsumerAuthApiUrl, getCoreApiUrl, getUser } from './config';
|
|
14
|
+
|
|
15
|
+
export type SessionEnv = 'dev' | 'prod';
|
|
16
|
+
|
|
17
|
+
export interface Session {
|
|
18
|
+
/** Tenant slug the app is actually scoped to (getTenant = signed-in tenant,
|
|
19
|
+
* falling back to the pre-auth choice). Null when neither is set. */
|
|
20
|
+
tenant: string | null;
|
|
21
|
+
/** Human label for the tenant — slug today; callers must not compute their own. */
|
|
22
|
+
tenantName: string;
|
|
23
|
+
/** dev | prod — derived from the resolved host, never a stored word. */
|
|
24
|
+
env: SessionEnv;
|
|
25
|
+
/** The actual backend host — a host can't be ambiguous the way a word can. */
|
|
26
|
+
host: string;
|
|
27
|
+
actorId: string | null;
|
|
28
|
+
email: string | null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function hostOf(u: string | undefined | null): string {
|
|
32
|
+
if (!u) return '';
|
|
33
|
+
try { return new URL(u).host; } catch { return u; }
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Is a resolved base URL a dev backend? Keyed on the hostname (dev-app…,
|
|
37
|
+
* dev-consumer-auth…) so it matches wherever the request goes. */
|
|
38
|
+
export function isDevHost(u: string | undefined | null): boolean {
|
|
39
|
+
const h = hostOf(u);
|
|
40
|
+
return !!h && (h.includes('dev-') || /(^|\.)dev\./.test(h));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Compute the session from the live SDK config. Plain function — a host hook
|
|
44
|
+
* wraps this for reactivity; imperative code can call it directly. */
|
|
45
|
+
export function getSession(): Session {
|
|
46
|
+
let consumerUrl = '';
|
|
47
|
+
try { consumerUrl = getConsumerAuthApiUrl(); } catch { /* not configured yet */ }
|
|
48
|
+
let coreUrl = '';
|
|
49
|
+
try { coreUrl = getCoreApiUrl(); } catch { /* not configured yet */ }
|
|
50
|
+
|
|
51
|
+
const tenant = getTenant() || null;
|
|
52
|
+
const user = getUser();
|
|
53
|
+
|
|
54
|
+
return {
|
|
55
|
+
tenant,
|
|
56
|
+
tenantName: tenant || '—',
|
|
57
|
+
env: isDevHost(consumerUrl) || isDevHost(coreUrl) ? 'dev' : 'prod',
|
|
58
|
+
host: hostOf(consumerUrl || coreUrl),
|
|
59
|
+
actorId: user?.actorId ?? null,
|
|
60
|
+
email: user?.email ?? null,
|
|
61
|
+
};
|
|
62
|
+
}
|