@amodalai/react 0.1.16 → 0.1.18
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/client/runtime-client.d.ts +1 -13
- package/dist/client/runtime-client.d.ts.map +1 -1
- package/dist/client.js +23 -42
- package/dist/client.js.map +1 -1
- package/dist/provider.d.ts +2 -5
- package/dist/provider.d.ts.map +1 -1
- package/dist/react.css +1 -1
- package/dist/react.js +170 -170
- package/dist/react.js.map +1 -1
- package/dist/widget/MessageList.d.ts +2 -1
- package/dist/widget/MessageList.d.ts.map +1 -1
- package/dist/widget.js +563 -507
- package/dist/widget.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
import { SSEEvent, TaskStatus, StoreDefinitionInfo, StoreListResult, StoreDocumentResult } from '../types';
|
|
2
2
|
export interface RuntimeClientOptions {
|
|
3
3
|
runtimeUrl: string;
|
|
4
|
-
appId: string;
|
|
5
4
|
getToken?: () => string | Promise<string> | null | undefined;
|
|
6
5
|
}
|
|
7
6
|
/**
|
|
8
7
|
* Client for the Amodal runtime's repo routes.
|
|
9
|
-
* Targets POST /chat, POST /task, GET /task/:id, GET /task/:id/stream.
|
|
10
8
|
*/
|
|
11
9
|
export declare class RuntimeClient {
|
|
12
10
|
private readonly runtimeUrl;
|
|
13
|
-
private readonly appId;
|
|
14
11
|
private readonly getToken?;
|
|
15
12
|
constructor(options: RuntimeClientOptions);
|
|
16
13
|
private authHeaders;
|
|
@@ -25,7 +22,7 @@ export declare class RuntimeClient {
|
|
|
25
22
|
/**
|
|
26
23
|
* Start a fire-and-forget task via POST /task.
|
|
27
24
|
*/
|
|
28
|
-
startTask(prompt: string
|
|
25
|
+
startTask(prompt: string): Promise<{
|
|
29
26
|
task_id: string;
|
|
30
27
|
}>;
|
|
31
28
|
/**
|
|
@@ -36,13 +33,7 @@ export declare class RuntimeClient {
|
|
|
36
33
|
* Stream task events via GET /task/:id/stream.
|
|
37
34
|
*/
|
|
38
35
|
streamTask(taskId: string, signal?: AbortSignal): AsyncGenerator<SSEEvent>;
|
|
39
|
-
/**
|
|
40
|
-
* List all store definitions with document counts.
|
|
41
|
-
*/
|
|
42
36
|
getStores(signal?: AbortSignal): Promise<StoreDefinitionInfo[]>;
|
|
43
|
-
/**
|
|
44
|
-
* List documents from a store with optional filtering.
|
|
45
|
-
*/
|
|
46
37
|
getStoreDocuments(storeName: string, options?: {
|
|
47
38
|
filter?: Record<string, unknown>;
|
|
48
39
|
sort?: string;
|
|
@@ -50,9 +41,6 @@ export declare class RuntimeClient {
|
|
|
50
41
|
offset?: number;
|
|
51
42
|
signal?: AbortSignal;
|
|
52
43
|
}): Promise<StoreListResult>;
|
|
53
|
-
/**
|
|
54
|
-
* Get a single document by key, optionally with version history.
|
|
55
|
-
*/
|
|
56
44
|
getStoreDocument(storeName: string, key: string, signal?: AbortSignal): Promise<StoreDocumentResult>;
|
|
57
45
|
}
|
|
58
46
|
//# sourceMappingURL=runtime-client.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime-client.d.ts","sourceRoot":"","sources":["../../src/client/runtime-client.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,mBAAmB,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAGhH,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,
|
|
1
|
+
{"version":3,"file":"runtime-client.d.ts","sourceRoot":"","sources":["../../src/client/runtime-client.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,mBAAmB,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAGhH,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,IAAI,GAAG,SAAS,CAAC;CAC9D;AAED;;GAEG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAoD;gBAElE,OAAO,EAAE,oBAAoB;YAK3B,WAAW;IAWzB;;OAEG;IACI,UAAU,CACf,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;QACR,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAClC,MAAM,CAAC,EAAE,WAAW,CAAC;KACtB,GACA,cAAc,CAAC,QAAQ,CAAC;IAoB3B;;OAEG;IACG,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAmB7D;;OAEG;IACG,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAcxD;;OAEG;IACI,UAAU,CACf,MAAM,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,WAAW,GACnB,cAAc,CAAC,QAAQ,CAAC;IAUrB,SAAS,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,mBAAmB,EAAE,CAAC;IAY/D,iBAAiB,CACrB,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE;QACR,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACjC,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,MAAM,CAAC,EAAE,WAAW,CAAC;KACtB,GACA,OAAO,CAAC,eAAe,CAAC;IA0BrB,gBAAgB,CACpB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,EACX,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,mBAAmB,CAAC;CAahC"}
|
package/dist/client.js
CHANGED
|
@@ -1,19 +1,18 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var n = (h, s, t) =>
|
|
4
|
-
import { b as
|
|
5
|
-
import { c as A, g as T, l as B, p as
|
|
1
|
+
var f = Object.defineProperty;
|
|
2
|
+
var k = (h, s, t) => s in h ? f(h, s, { enumerable: !0, configurable: !0, writable: !0, value: t }) : h[s] = t;
|
|
3
|
+
var n = (h, s, t) => k(h, typeof s != "symbol" ? s + "" : s, t);
|
|
4
|
+
import { b as p, e as w, s as g, T as y, W as S, a as b } from "./event-bus-h26clqbZ.js";
|
|
5
|
+
import { c as A, g as T, l as B, p as H, u as P } from "./event-bus-h26clqbZ.js";
|
|
6
6
|
/**
|
|
7
7
|
* @license
|
|
8
8
|
* Copyright 2025 Amodal Labs, Inc.
|
|
9
9
|
* SPDX-License-Identifier: MIT
|
|
10
10
|
*/
|
|
11
|
-
class
|
|
11
|
+
class I {
|
|
12
12
|
constructor(s) {
|
|
13
13
|
n(this, "runtimeUrl");
|
|
14
|
-
n(this, "appId");
|
|
15
14
|
n(this, "getToken");
|
|
16
|
-
this.runtimeUrl = s.runtimeUrl.replace(/\/$/, ""), this.
|
|
15
|
+
this.runtimeUrl = s.runtimeUrl.replace(/\/$/, ""), this.getToken = s.getToken;
|
|
17
16
|
}
|
|
18
17
|
async authHeaders() {
|
|
19
18
|
const s = {};
|
|
@@ -28,12 +27,11 @@ class x {
|
|
|
28
27
|
*/
|
|
29
28
|
async *chatStream(s, t) {
|
|
30
29
|
const e = `${this.runtimeUrl}/chat`, a = {
|
|
31
|
-
message: s
|
|
32
|
-
app_id: this.appId
|
|
30
|
+
message: s
|
|
33
31
|
};
|
|
34
32
|
t != null && t.sessionId && (a.session_id = t.sessionId), t != null && t.context && (a.context = t.context);
|
|
35
33
|
const o = await this.authHeaders();
|
|
36
|
-
yield*
|
|
34
|
+
yield* p(e, a, {
|
|
37
35
|
signal: t == null ? void 0 : t.signal,
|
|
38
36
|
headers: o
|
|
39
37
|
});
|
|
@@ -41,29 +39,21 @@ class x {
|
|
|
41
39
|
/**
|
|
42
40
|
* Start a fire-and-forget task via POST /task.
|
|
43
41
|
*/
|
|
44
|
-
async startTask(s
|
|
45
|
-
const
|
|
46
|
-
prompt: s,
|
|
47
|
-
app_id: this.appId
|
|
48
|
-
};
|
|
49
|
-
t && (o.app_token = t);
|
|
50
|
-
const l = await fetch(e, {
|
|
42
|
+
async startTask(s) {
|
|
43
|
+
const t = `${this.runtimeUrl}/task`, e = { prompt: s }, a = await this.authHeaders(), o = await fetch(t, {
|
|
51
44
|
method: "POST",
|
|
52
45
|
headers: { "Content-Type": "application/json", ...a },
|
|
53
|
-
body: JSON.stringify(
|
|
46
|
+
body: JSON.stringify(e)
|
|
54
47
|
});
|
|
55
|
-
if (!
|
|
56
|
-
throw new Error(`Start task failed: ${String(
|
|
57
|
-
return await
|
|
48
|
+
if (!o.ok)
|
|
49
|
+
throw new Error(`Start task failed: ${String(o.status)} ${o.statusText}`);
|
|
50
|
+
return await o.json();
|
|
58
51
|
}
|
|
59
52
|
/**
|
|
60
53
|
* Get task status via GET /task/:id.
|
|
61
54
|
*/
|
|
62
55
|
async getTaskStatus(s) {
|
|
63
|
-
const t = `${this.runtimeUrl}/task/${s}`, e = await this.authHeaders(), a = await fetch(t, {
|
|
64
|
-
method: "GET",
|
|
65
|
-
headers: e
|
|
66
|
-
});
|
|
56
|
+
const t = `${this.runtimeUrl}/task/${s}`, e = await this.authHeaders(), a = await fetch(t, { headers: e });
|
|
67
57
|
if (!a.ok)
|
|
68
58
|
throw new Error(`Get task status failed: ${String(a.status)} ${a.statusText}`);
|
|
69
59
|
return await a.json();
|
|
@@ -78,18 +68,12 @@ class x {
|
|
|
78
68
|
// ---------------------------------------------------------------------------
|
|
79
69
|
// Store API
|
|
80
70
|
// ---------------------------------------------------------------------------
|
|
81
|
-
/**
|
|
82
|
-
* List all store definitions with document counts.
|
|
83
|
-
*/
|
|
84
71
|
async getStores(s) {
|
|
85
72
|
const t = `${this.runtimeUrl}/api/stores`, e = await this.authHeaders(), a = await fetch(t, { headers: e, signal: s });
|
|
86
73
|
if (!a.ok)
|
|
87
74
|
throw new Error(`Failed to fetch stores: ${String(a.status)}`);
|
|
88
75
|
return (await a.json()).stores;
|
|
89
76
|
}
|
|
90
|
-
/**
|
|
91
|
-
* List documents from a store with optional filtering.
|
|
92
|
-
*/
|
|
93
77
|
async getStoreDocuments(s, t) {
|
|
94
78
|
const e = new URLSearchParams();
|
|
95
79
|
t != null && t.filter && e.set("filter", JSON.stringify(t.filter)), t != null && t.sort && e.set("sort", t.sort), (t == null ? void 0 : t.limit) !== void 0 && e.set("limit", String(t.limit)), (t == null ? void 0 : t.offset) !== void 0 && e.set("offset", String(t.offset));
|
|
@@ -98,9 +82,6 @@ class x {
|
|
|
98
82
|
throw new Error(`Failed to fetch store documents: ${String(r.status)}`);
|
|
99
83
|
return await r.json();
|
|
100
84
|
}
|
|
101
|
-
/**
|
|
102
|
-
* Get a single document by key, optionally with version history.
|
|
103
|
-
*/
|
|
104
85
|
async getStoreDocument(s, t, e) {
|
|
105
86
|
const a = `${this.runtimeUrl}/api/stores/${s}/${encodeURIComponent(t)}`, o = await this.authHeaders(), l = await fetch(a, { headers: o, signal: e });
|
|
106
87
|
if (!l.ok) {
|
|
@@ -154,7 +135,7 @@ class C {
|
|
|
154
135
|
if (!this.started) {
|
|
155
136
|
this.started = !0;
|
|
156
137
|
try {
|
|
157
|
-
const s =
|
|
138
|
+
const s = g(
|
|
158
139
|
this.serverUrl,
|
|
159
140
|
this.request,
|
|
160
141
|
this.abortController.signal,
|
|
@@ -372,7 +353,7 @@ class $ extends y {
|
|
|
372
353
|
toolCalls: [],
|
|
373
354
|
skillsUsed: [],
|
|
374
355
|
kbProposals: []
|
|
375
|
-
}, o = /* @__PURE__ */ new Map(), l =
|
|
356
|
+
}, o = /* @__PURE__ */ new Map(), l = g(
|
|
376
357
|
this.config.serverUrl,
|
|
377
358
|
{
|
|
378
359
|
message: t,
|
|
@@ -480,16 +461,16 @@ class $ extends y {
|
|
|
480
461
|
export {
|
|
481
462
|
$ as ChatClient,
|
|
482
463
|
C as ChatStream,
|
|
483
|
-
|
|
464
|
+
I as RuntimeClient,
|
|
484
465
|
y as TypedEventEmitter,
|
|
485
466
|
A as createChatClient,
|
|
486
467
|
b as createSession,
|
|
487
468
|
T as getSessionHistory,
|
|
488
469
|
B as listSessions,
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
470
|
+
H as parseSSELine,
|
|
471
|
+
g as streamChat,
|
|
472
|
+
p as streamSSE,
|
|
492
473
|
w as streamSSEGet,
|
|
493
|
-
|
|
474
|
+
P as updateSession
|
|
494
475
|
};
|
|
495
476
|
//# sourceMappingURL=client.js.map
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sources":["../src/client/runtime-client.ts","../src/client/ChatStream.ts","../src/client/ChatClient.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2025 Amodal Labs, Inc.\n * SPDX-License-Identifier: MIT\n */\n\nimport type { SSEEvent, TaskStatus, StoreDefinitionInfo, StoreListResult, StoreDocumentResult } from '../types';\nimport { streamSSE, streamSSEGet } from './sse-client';\n\nexport interface RuntimeClientOptions {\n runtimeUrl: string;\n appId: string;\n getToken?: () => string | Promise<string> | null | undefined;\n}\n\n/**\n * Client for the Amodal runtime's repo routes.\n * Targets POST /chat, POST /task, GET /task/:id, GET /task/:id/stream.\n */\nexport class RuntimeClient {\n private readonly runtimeUrl: string;\n private readonly appId: string;\n private readonly getToken?: () => string | Promise<string> | null | undefined;\n\n constructor(options: RuntimeClientOptions) {\n this.runtimeUrl = options.runtimeUrl.replace(/\\/$/, '');\n this.appId = options.appId;\n this.getToken = options.getToken;\n }\n\n private async authHeaders(): Promise<Record<string, string>> {\n const headers: Record<string, string> = {};\n if (this.getToken) {\n const token = await this.getToken();\n if (token) {\n headers['Authorization'] = `Bearer ${token}`;\n }\n }\n return headers;\n }\n\n /**\n * Stream a chat message via POST /chat.\n */\n async *chatStream(\n message: string,\n options?: {\n sessionId?: string;\n context?: Record<string, unknown>;\n signal?: AbortSignal;\n },\n ): AsyncGenerator<SSEEvent> {\n const url = `${this.runtimeUrl}/chat`;\n const body: Record<string, unknown> = {\n message,\n app_id: this.appId,\n };\n if (options?.sessionId) {\n body['session_id'] = options.sessionId;\n }\n if (options?.context) {\n body['context'] = options.context;\n }\n\n const headers = await this.authHeaders();\n\n yield* streamSSE(url, body, {\n signal: options?.signal,\n headers,\n });\n }\n\n /**\n * Start a fire-and-forget task via POST /task.\n */\n async startTask(\n prompt: string,\n appToken?: string,\n ): Promise<{ task_id: string }> {\n const url = `${this.runtimeUrl}/task`;\n const headers = await this.authHeaders();\n\n const body: Record<string, unknown> = {\n prompt,\n app_id: this.appId,\n };\n if (appToken) {\n body['app_token'] = appToken;\n }\n\n const response = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', ...headers },\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n throw new Error(`Start task failed: ${String(response.status)} ${response.statusText}`);\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Server response\n return (await response.json()) as { task_id: string };\n }\n\n /**\n * Get task status via GET /task/:id.\n */\n async getTaskStatus(taskId: string): Promise<TaskStatus> {\n const url = `${this.runtimeUrl}/task/${taskId}`;\n const headers = await this.authHeaders();\n\n const response = await fetch(url, {\n method: 'GET',\n headers,\n });\n\n if (!response.ok) {\n throw new Error(`Get task status failed: ${String(response.status)} ${response.statusText}`);\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Server response\n return (await response.json()) as TaskStatus;\n }\n\n /**\n * Stream task events via GET /task/:id/stream.\n */\n async *streamTask(\n taskId: string,\n signal?: AbortSignal,\n ): AsyncGenerator<SSEEvent> {\n const url = `${this.runtimeUrl}/task/${taskId}/stream`;\n const headers = await this.authHeaders();\n\n yield* streamSSEGet(url, { signal, headers });\n }\n\n // ---------------------------------------------------------------------------\n // Store API\n // ---------------------------------------------------------------------------\n\n /**\n * List all store definitions with document counts.\n */\n async getStores(signal?: AbortSignal): Promise<StoreDefinitionInfo[]> {\n const url = `${this.runtimeUrl}/api/stores`;\n const headers = await this.authHeaders();\n\n const response = await fetch(url, { headers, signal });\n if (!response.ok) {\n throw new Error(`Failed to fetch stores: ${String(response.status)}`);\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Server response\n const body = (await response.json()) as { stores: StoreDefinitionInfo[] };\n return body.stores;\n }\n\n /**\n * List documents from a store with optional filtering.\n */\n async getStoreDocuments(\n storeName: string,\n options?: {\n filter?: Record<string, unknown>;\n sort?: string;\n limit?: number;\n offset?: number;\n signal?: AbortSignal;\n },\n ): Promise<StoreListResult> {\n const params = new URLSearchParams();\n if (options?.filter) {\n params.set('filter', JSON.stringify(options.filter));\n }\n if (options?.sort) {\n params.set('sort', options.sort);\n }\n if (options?.limit !== undefined) {\n params.set('limit', String(options.limit));\n }\n if (options?.offset !== undefined) {\n params.set('offset', String(options.offset));\n }\n\n const qs = params.toString();\n const url = `${this.runtimeUrl}/api/stores/${storeName}${qs ? `?${qs}` : ''}`;\n const headers = await this.authHeaders();\n\n const response = await fetch(url, { headers, signal: options?.signal });\n if (!response.ok) {\n throw new Error(`Failed to fetch store documents: ${String(response.status)}`);\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Server response\n return (await response.json()) as StoreListResult;\n }\n\n /**\n * Get a single document by key, optionally with version history.\n */\n async getStoreDocument(\n storeName: string,\n key: string,\n signal?: AbortSignal,\n ): Promise<StoreDocumentResult> {\n const url = `${this.runtimeUrl}/api/stores/${storeName}/${encodeURIComponent(key)}`;\n const headers = await this.authHeaders();\n\n const response = await fetch(url, { headers, signal });\n if (!response.ok) {\n if (response.status === 404) {\n return { document: null, history: [] };\n }\n throw new Error(`Failed to fetch store document: ${String(response.status)}`);\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Server response\n return (await response.json()) as StoreDocumentResult;\n }\n}\n","/**\n * @license\n * Copyright 2025 Amodal Labs, Inc.\n * SPDX-License-Identifier: MIT\n */\n\nimport type {\n SSEEvent,\n ToolCallInfo,\n KBProposalInfo,\n AskUserQuestion,\n} from '../types';\nimport type { ChatStreamRequest } from './chat-api';\nimport { streamChat } from './chat-api';\n\n/**\n * Full response from a completed chat stream.\n */\nexport interface ChatResponse {\n text: string;\n toolCalls: ToolCallInfo[];\n skillsUsed: string[];\n kbProposals: KBProposalInfo[];\n}\n\ntype StreamEventHandler<T> = (data: T) => void;\n\n/**\n * A streaming chat response handle.\n * Register `.on()` handlers then the stream starts automatically.\n */\nexport class ChatStream {\n private handlers: {\n text: Array<StreamEventHandler<{ text: string }>>;\n tool_call: Array<StreamEventHandler<{ tool: string; params: Record<string, unknown>; toolId: string }>>;\n tool_result: Array<StreamEventHandler<{ tool: string; data: unknown; duration_ms?: number; toolId: string }>>;\n skill_activated: Array<StreamEventHandler<{ name: string }>>;\n kb_proposal: Array<StreamEventHandler<KBProposalInfo>>;\n widget: Array<StreamEventHandler<{ widgetType: string; data: Record<string, unknown> }>>;\n ask_user: Array<StreamEventHandler<{ askId: string; questions: AskUserQuestion[] }>>;\n error: Array<StreamEventHandler<{ message: string }>>;\n done: Array<StreamEventHandler<ChatResponse>>;\n } = {\n text: [],\n tool_call: [],\n tool_result: [],\n skill_activated: [],\n kb_proposal: [],\n widget: [],\n ask_user: [],\n error: [],\n done: [],\n };\n\n private abortController: AbortController;\n private started = false;\n private response: ChatResponse = {\n text: '',\n toolCalls: [],\n skillsUsed: [],\n kbProposals: [],\n };\n private toolCallNames = new Map<string, string>();\n\n private token?: string;\n\n constructor(\n private serverUrl: string,\n private request: ChatStreamRequest,\n token?: string,\n ) {\n this.abortController = new AbortController();\n this.token = token;\n // Start on next microtick so .on() calls can register first\n queueMicrotask(() => this.start());\n }\n\n on(event: 'text', handler: StreamEventHandler<{ text: string }>): this;\n on(event: 'tool_call', handler: StreamEventHandler<{ tool: string; params: Record<string, unknown>; toolId: string }>): this;\n on(event: 'tool_result', handler: StreamEventHandler<{ tool: string; data: unknown; duration_ms?: number; toolId: string }>): this;\n on(event: 'skill_activated', handler: StreamEventHandler<{ name: string }>): this;\n on(event: 'kb_proposal', handler: StreamEventHandler<KBProposalInfo>): this;\n on(event: 'widget', handler: StreamEventHandler<{ widgetType: string; data: Record<string, unknown> }>): this;\n on(event: 'ask_user', handler: StreamEventHandler<{ askId: string; questions: AskUserQuestion[] }>): this;\n on(event: 'error', handler: StreamEventHandler<{ message: string }>): this;\n on(event: 'done', handler: StreamEventHandler<ChatResponse>): this;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- overload implementation requires broad type\n on(event: string, handler: StreamEventHandler<any>): this {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- overload dispatch key narrowing\n const key = event as keyof typeof this.handlers;\n if (key in this.handlers) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- overload dispatch\n (this.handlers[key] as Array<StreamEventHandler<unknown>>).push(handler);\n }\n return this;\n }\n\n /** Cancel the stream. */\n abort(): void {\n this.abortController.abort();\n }\n\n private async start(): Promise<void> {\n if (this.started) return;\n this.started = true;\n\n try {\n const stream = streamChat(\n this.serverUrl,\n this.request,\n this.abortController.signal,\n this.token,\n );\n\n for await (const event of stream) {\n this.processEvent(event);\n }\n\n // Emit done\n for (const handler of this.handlers.done) {\n handler(this.response);\n }\n } catch (err) {\n if (!(err instanceof DOMException && err.name === 'AbortError')) {\n const message = err instanceof Error ? err.message : 'Unknown error';\n for (const handler of this.handlers.error) {\n handler({ message });\n }\n }\n }\n }\n\n private processEvent(event: SSEEvent): void {\n switch (event.type) {\n case 'text_delta':\n this.response.text += event.content;\n for (const handler of this.handlers.text) {\n handler({ text: event.content });\n }\n break;\n case 'tool_call_start':\n this.toolCallNames.set(event.tool_id, event.tool_name);\n for (const handler of this.handlers.tool_call) {\n handler({ tool: event.tool_name, params: event.parameters, toolId: event.tool_id });\n }\n this.response.toolCalls.push({\n toolId: event.tool_id,\n toolName: event.tool_name,\n parameters: event.parameters,\n status: 'running',\n });\n break;\n case 'tool_call_result': {\n const toolName = this.toolCallNames.get(event.tool_id) ?? '';\n for (const handler of this.handlers.tool_result) {\n handler({ tool: toolName, data: event.result, duration_ms: event.duration_ms, toolId: event.tool_id });\n }\n // Update status in response\n const tc = this.response.toolCalls.find((t) => t.toolId === event.tool_id);\n if (tc) {\n tc.status = event.status;\n tc.result = event.result;\n tc.duration_ms = event.duration_ms;\n tc.error = event.error;\n }\n break;\n }\n case 'skill_activated':\n this.response.skillsUsed.push(event.skill);\n for (const handler of this.handlers.skill_activated) {\n handler({ name: event.skill });\n }\n break;\n case 'kb_proposal': {\n const proposal: KBProposalInfo = {\n scope: event.scope,\n title: event.title,\n reasoning: event.reasoning,\n };\n this.response.kbProposals.push(proposal);\n for (const handler of this.handlers.kb_proposal) {\n handler(proposal);\n }\n break;\n }\n case 'ask_user':\n for (const handler of this.handlers.ask_user) {\n handler({ askId: event.ask_id, questions: event.questions });\n }\n break;\n case 'widget':\n for (const handler of this.handlers.widget) {\n handler({ widgetType: event.widget_type, data: event.data });\n }\n break;\n case 'error':\n for (const handler of this.handlers.error) {\n handler({ message: event.message });\n }\n break;\n case 'init':\n case 'done':\n // Init handled by ChatClient, done triggers after loop\n break;\n default:\n break;\n }\n }\n}\n","/**\n * @license\n * Copyright 2025 Amodal Labs, Inc.\n * SPDX-License-Identifier: MIT\n */\n\nimport { TypedEventEmitter } from './EventEmitter';\nimport { ChatStream } from './ChatStream';\nimport type { ChatResponse } from './ChatStream';\nimport { createSession, streamChat } from './chat-api';\nimport type { ChatUser, ChatMessage, AssistantTextMessage, ToolCallInfo, KBProposalInfo } from '../types';\nimport { WidgetEventBus } from '../events/event-bus';\nimport type { WidgetEvent, EntityExtractor, ToolExecutedEvent, SkillActivatedEvent, WidgetRenderedEvent, KBProposalEvent } from '../events/types';\n\n/**\n * Configuration for the ChatClient.\n */\nexport interface ChatClientConfig {\n serverUrl: string;\n user: ChatUser;\n /** Bearer token (API key or JWT) for authenticated requests. */\n token?: string;\n /** Custom entity extractors. If provided, replaces the default extractor. */\n entityExtractors?: EntityExtractor[];\n}\n\n/**\n * Events emitted by the ChatClient.\n */\nexport interface ClientEvents {\n connected: undefined;\n disconnected: undefined;\n reconnecting: number;\n message: ChatMessage;\n streaming_start: undefined;\n streaming_end: undefined;\n error: Error;\n tool_executed: ToolExecutedEvent;\n skill_activated: SkillActivatedEvent;\n widget_rendered: WidgetRenderedEvent;\n kb_proposal_received: KBProposalEvent;\n entity_referenced: WidgetEvent;\n}\n\nlet msgCounter = 0;\nfunction makeId(): string {\n msgCounter++;\n return `msg-${Date.now()}-${String(msgCounter)}`;\n}\n\n/**\n * Headless chat client for framework-agnostic integrations.\n * Manages session lifecycle, message history, and SSE streaming.\n */\nexport class ChatClient extends TypedEventEmitter<ClientEvents> {\n private config: ChatClientConfig;\n private sessionId: string | null = null;\n private _messages: ChatMessage[] = [];\n private _isConnected = false;\n private _isStreaming = false;\n private connectAttempt = 0;\n private maxReconnectAttempts = 3;\n private _eventBus: WidgetEventBus;\n\n constructor(config: ChatClientConfig) {\n super();\n this.config = config;\n this._eventBus = new WidgetEventBus();\n if (config.entityExtractors) {\n this._eventBus.setExtractors(config.entityExtractors);\n }\n // Forward entity_referenced events from bus to client events\n this._eventBus.on('entity_referenced', (e) => {\n this.emit('entity_referenced', e);\n });\n }\n\n /** The widget event bus. Subscribe to agent-driven events here. */\n get events(): WidgetEventBus {\n return this._eventBus;\n }\n\n /** Whether the client has an active session. */\n get isConnected(): boolean {\n return this._isConnected;\n }\n\n /** Whether a response is currently streaming. */\n get isStreaming(): boolean {\n return this._isStreaming;\n }\n\n /** Current session ID, or null if not connected. */\n getSessionId(): string | null {\n return this.sessionId;\n }\n\n /** Readonly message history. */\n get messages(): readonly ChatMessage[] {\n return this._messages;\n }\n\n /** Establish a session with the server. */\n async connect(): Promise<void> {\n try {\n const session = await createSession(\n this.config.serverUrl,\n this.config.user,\n this.config.token,\n );\n this.sessionId = session.session_id;\n this._isConnected = true;\n this.connectAttempt = 0;\n this.emit('connected', undefined);\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n this.emit('error', error);\n throw error;\n }\n }\n\n /** Disconnect and clean up. */\n async disconnect(): Promise<void> {\n this.sessionId = null;\n this._isConnected = false;\n this._isStreaming = false;\n this.emit('disconnected', undefined);\n }\n\n /** Clear message history. */\n clearHistory(): void {\n this._messages = [];\n }\n\n /**\n * Send a message and wait for the full response.\n * Auto-connects if not already connected.\n */\n async send(text: string): Promise<ChatResponse> {\n if (!this._isConnected) {\n await this.connect();\n }\n\n // Add user message\n const userMsg: ChatMessage = {\n type: 'user',\n id: makeId(),\n text,\n timestamp: new Date().toISOString(),\n };\n this._messages.push(userMsg);\n this.emit('message', userMsg);\n\n // Create assistant message placeholder\n const assistantMsg: AssistantTextMessage = {\n type: 'assistant_text',\n id: makeId(),\n text: '',\n toolCalls: [],\n confirmations: [],\n skillActivations: [],\n kbProposals: [],\n widgets: [],\n contentBlocks: [],\n timestamp: new Date().toISOString(),\n };\n this._messages.push(assistantMsg);\n this.emit('message', assistantMsg);\n\n this._isStreaming = true;\n this.emit('streaming_start', undefined);\n\n try {\n const response = await this.streamInternal(text, assistantMsg);\n return response;\n } catch (err) {\n // Try reconnection\n if (this.connectAttempt < this.maxReconnectAttempts) {\n return await this.reconnectAndRetry(text, assistantMsg);\n }\n throw err;\n } finally {\n this._isStreaming = false;\n this.emit('streaming_end', undefined);\n }\n }\n\n /**\n * Stream a message, returning a ChatStream handle for event-based consumption.\n */\n stream(text: string): ChatStream {\n // Add user message\n const userMsg: ChatMessage = {\n type: 'user',\n id: makeId(),\n text,\n timestamp: new Date().toISOString(),\n };\n this._messages.push(userMsg);\n this.emit('message', userMsg);\n\n this._isStreaming = true;\n this.emit('streaming_start', undefined);\n\n const chatStream = new ChatStream(this.config.serverUrl, {\n message: text,\n session_id: this.sessionId ?? undefined,\n role: this.config.user.role,\n }, this.config.token);\n\n // Track streaming state\n chatStream.on('done', (response) => {\n // Add assistant message to history\n const assistantMsg: AssistantTextMessage = {\n type: 'assistant_text',\n id: makeId(),\n text: response.text,\n toolCalls: response.toolCalls,\n confirmations: [],\n skillActivations: response.skillsUsed,\n kbProposals: response.kbProposals,\n widgets: [],\n contentBlocks: [],\n timestamp: new Date().toISOString(),\n };\n this._messages.push(assistantMsg);\n this.emit('message', assistantMsg);\n this._isStreaming = false;\n this.emit('streaming_end', undefined);\n });\n\n chatStream.on('error', (err) => {\n this._isStreaming = false;\n this.emit('streaming_end', undefined);\n this.emit('error', new Error(err.message));\n });\n\n return chatStream;\n }\n\n private async streamInternal(\n text: string,\n assistantMsg: AssistantTextMessage,\n ): Promise<ChatResponse> {\n const response: ChatResponse = {\n text: '',\n toolCalls: [],\n skillsUsed: [],\n kbProposals: [],\n };\n\n const pendingToolCalls = new Map<string, { toolName: string; parameters: Record<string, unknown> }>();\n\n const stream = streamChat(\n this.config.serverUrl,\n {\n message: text,\n session_id: this.sessionId ?? undefined,\n role: this.config.user.role,\n },\n undefined,\n this.config.token,\n );\n\n for await (const event of stream) {\n switch (event.type) {\n case 'init':\n this.sessionId = event.session_id;\n break;\n case 'text_delta':\n response.text += event.content;\n assistantMsg.text += event.content;\n break;\n case 'tool_call_start': {\n const tc: ToolCallInfo = {\n toolId: event.tool_id,\n toolName: event.tool_name,\n parameters: event.parameters,\n status: 'running',\n };\n response.toolCalls.push(tc);\n assistantMsg.toolCalls = [...assistantMsg.toolCalls, tc];\n pendingToolCalls.set(event.tool_id, {\n toolName: event.tool_name,\n parameters: event.parameters,\n });\n break;\n }\n case 'tool_call_result': {\n const existing = response.toolCalls.find((t) => t.toolId === event.tool_id);\n if (existing) {\n existing.status = event.status;\n existing.result = event.result;\n existing.duration_ms = event.duration_ms;\n existing.error = event.error;\n }\n assistantMsg.toolCalls = assistantMsg.toolCalls.map((t) =>\n t.toolId === event.tool_id\n ? { ...t, status: event.status, result: event.result, duration_ms: event.duration_ms, error: event.error }\n : t,\n );\n\n const pending = pendingToolCalls.get(event.tool_id);\n pendingToolCalls.delete(event.tool_id);\n const toolEvent: ToolExecutedEvent = {\n type: 'tool_executed',\n toolName: pending?.toolName ?? '',\n toolId: event.tool_id,\n parameters: pending?.parameters ?? {},\n status: event.status,\n result: event.result,\n duration_ms: event.duration_ms,\n error: event.error,\n timestamp: event.timestamp,\n };\n this._eventBus.processEvent(toolEvent);\n this.emit('tool_executed', toolEvent);\n break;\n }\n case 'skill_activated': {\n response.skillsUsed.push(event.skill);\n assistantMsg.skillActivations = [...assistantMsg.skillActivations, event.skill];\n const skillEvent: SkillActivatedEvent = {\n type: 'skill_activated',\n skill: event.skill,\n timestamp: event.timestamp,\n };\n this._eventBus.processEvent(skillEvent);\n this.emit('skill_activated', skillEvent);\n break;\n }\n case 'kb_proposal': {\n const proposal: KBProposalInfo = {\n scope: event.scope,\n title: event.title,\n reasoning: event.reasoning,\n };\n response.kbProposals.push(proposal);\n assistantMsg.kbProposals = [...assistantMsg.kbProposals, proposal];\n const kbEvent: KBProposalEvent = {\n type: 'kb_proposal',\n proposal,\n timestamp: event.timestamp,\n };\n this._eventBus.processEvent(kbEvent);\n this.emit('kb_proposal_received', kbEvent);\n break;\n }\n case 'widget': {\n const widgetEvent: WidgetRenderedEvent = {\n type: 'widget_rendered',\n widgetType: event.widget_type,\n data: event.data,\n timestamp: event.timestamp,\n };\n this._eventBus.processEvent(widgetEvent);\n this.emit('widget_rendered', widgetEvent);\n break;\n }\n case 'error':\n throw new Error(event.message);\n case 'done':\n break;\n default:\n break;\n }\n }\n\n return response;\n }\n\n private async reconnectAndRetry(\n text: string,\n assistantMsg: AssistantTextMessage,\n ): Promise<ChatResponse> {\n this.connectAttempt++;\n this.emit('reconnecting', this.connectAttempt);\n\n // Exponential backoff: 100ms, 200ms, 400ms\n const delay = 100 * Math.pow(2, this.connectAttempt - 1);\n await new Promise((resolve) => setTimeout(resolve, delay));\n\n try {\n await this.connect();\n return await this.streamInternal(text, assistantMsg);\n } catch (err) {\n if (this.connectAttempt < this.maxReconnectAttempts) {\n return this.reconnectAndRetry(text, assistantMsg);\n }\n throw err;\n }\n }\n}\n"],"names":["RuntimeClient","options","__publicField","headers","token","message","url","body","streamSSE","prompt","appToken","response","taskId","signal","streamSSEGet","storeName","params","qs","key","ChatStream","serverUrl","request","event","handler","stream","streamChat","err","toolName","tc","t","proposal","msgCounter","makeId","ChatClient","TypedEventEmitter","config","WidgetEventBus","session","createSession","error","text","userMsg","assistantMsg","chatStream","pendingToolCalls","existing","pending","toolEvent","skillEvent","kbEvent","widgetEvent","delay","resolve"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"client.js","sources":["../src/client/runtime-client.ts","../src/client/ChatStream.ts","../src/client/ChatClient.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2025 Amodal Labs, Inc.\n * SPDX-License-Identifier: MIT\n */\n\nimport type { SSEEvent, TaskStatus, StoreDefinitionInfo, StoreListResult, StoreDocumentResult } from '../types';\nimport { streamSSE, streamSSEGet } from './sse-client';\n\nexport interface RuntimeClientOptions {\n runtimeUrl: string;\n getToken?: () => string | Promise<string> | null | undefined;\n}\n\n/**\n * Client for the Amodal runtime's repo routes.\n */\nexport class RuntimeClient {\n private readonly runtimeUrl: string;\n private readonly getToken?: () => string | Promise<string> | null | undefined;\n\n constructor(options: RuntimeClientOptions) {\n this.runtimeUrl = options.runtimeUrl.replace(/\\/$/, '');\n this.getToken = options.getToken;\n }\n\n private async authHeaders(): Promise<Record<string, string>> {\n const headers: Record<string, string> = {};\n if (this.getToken) {\n const token = await this.getToken();\n if (token) {\n headers['Authorization'] = `Bearer ${token}`;\n }\n }\n return headers;\n }\n\n /**\n * Stream a chat message via POST /chat.\n */\n async *chatStream(\n message: string,\n options?: {\n sessionId?: string;\n context?: Record<string, unknown>;\n signal?: AbortSignal;\n },\n ): AsyncGenerator<SSEEvent> {\n const url = `${this.runtimeUrl}/chat`;\n const body: Record<string, unknown> = {\n message,\n };\n if (options?.sessionId) {\n body['session_id'] = options.sessionId;\n }\n if (options?.context) {\n body['context'] = options.context;\n }\n\n const headers = await this.authHeaders();\n\n yield* streamSSE(url, body, {\n signal: options?.signal,\n headers,\n });\n }\n\n /**\n * Start a fire-and-forget task via POST /task.\n */\n async startTask(prompt: string): Promise<{ task_id: string }> {\n const url = `${this.runtimeUrl}/task`;\n const body: Record<string, unknown> = { prompt };\n const headers = await this.authHeaders();\n\n const response = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', ...headers },\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n throw new Error(`Start task failed: ${String(response.status)} ${response.statusText}`);\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Server response\n return (await response.json()) as { task_id: string };\n }\n\n /**\n * Get task status via GET /task/:id.\n */\n async getTaskStatus(taskId: string): Promise<TaskStatus> {\n const url = `${this.runtimeUrl}/task/${taskId}`;\n\n const headers = await this.authHeaders();\n const response = await fetch(url, { headers });\n\n if (!response.ok) {\n throw new Error(`Get task status failed: ${String(response.status)} ${response.statusText}`);\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Server response\n return (await response.json()) as TaskStatus;\n }\n\n /**\n * Stream task events via GET /task/:id/stream.\n */\n async *streamTask(\n taskId: string,\n signal?: AbortSignal,\n ): AsyncGenerator<SSEEvent> {\n const url = `${this.runtimeUrl}/task/${taskId}/stream`;\n const headers = await this.authHeaders();\n yield* streamSSEGet(url, { signal, headers });\n }\n\n // ---------------------------------------------------------------------------\n // Store API\n // ---------------------------------------------------------------------------\n\n async getStores(signal?: AbortSignal): Promise<StoreDefinitionInfo[]> {\n const url = `${this.runtimeUrl}/api/stores`;\n const authH = await this.authHeaders();\n const response = await fetch(url, { headers: authH, signal });\n if (!response.ok) {\n throw new Error(`Failed to fetch stores: ${String(response.status)}`);\n }\n // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Server response\n const body = (await response.json()) as { stores: StoreDefinitionInfo[] };\n return body.stores;\n }\n\n async getStoreDocuments(\n storeName: string,\n options?: {\n filter?: Record<string, unknown>;\n sort?: string;\n limit?: number;\n offset?: number;\n signal?: AbortSignal;\n },\n ): Promise<StoreListResult> {\n const params = new URLSearchParams();\n if (options?.filter) {\n params.set('filter', JSON.stringify(options.filter));\n }\n if (options?.sort) {\n params.set('sort', options.sort);\n }\n if (options?.limit !== undefined) {\n params.set('limit', String(options.limit));\n }\n if (options?.offset !== undefined) {\n params.set('offset', String(options.offset));\n }\n\n const qs = params.toString();\n const url = `${this.runtimeUrl}/api/stores/${storeName}${qs ? `?${qs}` : ''}`;\n const authH = await this.authHeaders();\n const response = await fetch(url, { headers: authH, signal: options?.signal });\n if (!response.ok) {\n throw new Error(`Failed to fetch store documents: ${String(response.status)}`);\n }\n // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Server response\n return (await response.json()) as StoreListResult;\n }\n\n async getStoreDocument(\n storeName: string,\n key: string,\n signal?: AbortSignal,\n ): Promise<StoreDocumentResult> {\n const url = `${this.runtimeUrl}/api/stores/${storeName}/${encodeURIComponent(key)}`;\n const authH = await this.authHeaders();\n const response = await fetch(url, { headers: authH, signal });\n if (!response.ok) {\n if (response.status === 404) {\n return { document: null, history: [] };\n }\n throw new Error(`Failed to fetch store document: ${String(response.status)}`);\n }\n // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- Server response\n return (await response.json()) as StoreDocumentResult;\n }\n}\n","/**\n * @license\n * Copyright 2025 Amodal Labs, Inc.\n * SPDX-License-Identifier: MIT\n */\n\nimport type {\n SSEEvent,\n ToolCallInfo,\n KBProposalInfo,\n AskUserQuestion,\n} from '../types';\nimport type { ChatStreamRequest } from './chat-api';\nimport { streamChat } from './chat-api';\n\n/**\n * Full response from a completed chat stream.\n */\nexport interface ChatResponse {\n text: string;\n toolCalls: ToolCallInfo[];\n skillsUsed: string[];\n kbProposals: KBProposalInfo[];\n}\n\ntype StreamEventHandler<T> = (data: T) => void;\n\n/**\n * A streaming chat response handle.\n * Register `.on()` handlers then the stream starts automatically.\n */\nexport class ChatStream {\n private handlers: {\n text: Array<StreamEventHandler<{ text: string }>>;\n tool_call: Array<StreamEventHandler<{ tool: string; params: Record<string, unknown>; toolId: string }>>;\n tool_result: Array<StreamEventHandler<{ tool: string; data: unknown; duration_ms?: number; toolId: string }>>;\n skill_activated: Array<StreamEventHandler<{ name: string }>>;\n kb_proposal: Array<StreamEventHandler<KBProposalInfo>>;\n widget: Array<StreamEventHandler<{ widgetType: string; data: Record<string, unknown> }>>;\n ask_user: Array<StreamEventHandler<{ askId: string; questions: AskUserQuestion[] }>>;\n error: Array<StreamEventHandler<{ message: string }>>;\n done: Array<StreamEventHandler<ChatResponse>>;\n } = {\n text: [],\n tool_call: [],\n tool_result: [],\n skill_activated: [],\n kb_proposal: [],\n widget: [],\n ask_user: [],\n error: [],\n done: [],\n };\n\n private abortController: AbortController;\n private started = false;\n private response: ChatResponse = {\n text: '',\n toolCalls: [],\n skillsUsed: [],\n kbProposals: [],\n };\n private toolCallNames = new Map<string, string>();\n\n private token?: string;\n\n constructor(\n private serverUrl: string,\n private request: ChatStreamRequest,\n token?: string,\n ) {\n this.abortController = new AbortController();\n this.token = token;\n // Start on next microtick so .on() calls can register first\n queueMicrotask(() => this.start());\n }\n\n on(event: 'text', handler: StreamEventHandler<{ text: string }>): this;\n on(event: 'tool_call', handler: StreamEventHandler<{ tool: string; params: Record<string, unknown>; toolId: string }>): this;\n on(event: 'tool_result', handler: StreamEventHandler<{ tool: string; data: unknown; duration_ms?: number; toolId: string }>): this;\n on(event: 'skill_activated', handler: StreamEventHandler<{ name: string }>): this;\n on(event: 'kb_proposal', handler: StreamEventHandler<KBProposalInfo>): this;\n on(event: 'widget', handler: StreamEventHandler<{ widgetType: string; data: Record<string, unknown> }>): this;\n on(event: 'ask_user', handler: StreamEventHandler<{ askId: string; questions: AskUserQuestion[] }>): this;\n on(event: 'error', handler: StreamEventHandler<{ message: string }>): this;\n on(event: 'done', handler: StreamEventHandler<ChatResponse>): this;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- overload implementation requires broad type\n on(event: string, handler: StreamEventHandler<any>): this {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- overload dispatch key narrowing\n const key = event as keyof typeof this.handlers;\n if (key in this.handlers) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- overload dispatch\n (this.handlers[key] as Array<StreamEventHandler<unknown>>).push(handler);\n }\n return this;\n }\n\n /** Cancel the stream. */\n abort(): void {\n this.abortController.abort();\n }\n\n private async start(): Promise<void> {\n if (this.started) return;\n this.started = true;\n\n try {\n const stream = streamChat(\n this.serverUrl,\n this.request,\n this.abortController.signal,\n this.token,\n );\n\n for await (const event of stream) {\n this.processEvent(event);\n }\n\n // Emit done\n for (const handler of this.handlers.done) {\n handler(this.response);\n }\n } catch (err) {\n if (!(err instanceof DOMException && err.name === 'AbortError')) {\n const message = err instanceof Error ? err.message : 'Unknown error';\n for (const handler of this.handlers.error) {\n handler({ message });\n }\n }\n }\n }\n\n private processEvent(event: SSEEvent): void {\n switch (event.type) {\n case 'text_delta':\n this.response.text += event.content;\n for (const handler of this.handlers.text) {\n handler({ text: event.content });\n }\n break;\n case 'tool_call_start':\n this.toolCallNames.set(event.tool_id, event.tool_name);\n for (const handler of this.handlers.tool_call) {\n handler({ tool: event.tool_name, params: event.parameters, toolId: event.tool_id });\n }\n this.response.toolCalls.push({\n toolId: event.tool_id,\n toolName: event.tool_name,\n parameters: event.parameters,\n status: 'running',\n });\n break;\n case 'tool_call_result': {\n const toolName = this.toolCallNames.get(event.tool_id) ?? '';\n for (const handler of this.handlers.tool_result) {\n handler({ tool: toolName, data: event.result, duration_ms: event.duration_ms, toolId: event.tool_id });\n }\n // Update status in response\n const tc = this.response.toolCalls.find((t) => t.toolId === event.tool_id);\n if (tc) {\n tc.status = event.status;\n tc.result = event.result;\n tc.duration_ms = event.duration_ms;\n tc.error = event.error;\n }\n break;\n }\n case 'skill_activated':\n this.response.skillsUsed.push(event.skill);\n for (const handler of this.handlers.skill_activated) {\n handler({ name: event.skill });\n }\n break;\n case 'kb_proposal': {\n const proposal: KBProposalInfo = {\n scope: event.scope,\n title: event.title,\n reasoning: event.reasoning,\n };\n this.response.kbProposals.push(proposal);\n for (const handler of this.handlers.kb_proposal) {\n handler(proposal);\n }\n break;\n }\n case 'ask_user':\n for (const handler of this.handlers.ask_user) {\n handler({ askId: event.ask_id, questions: event.questions });\n }\n break;\n case 'widget':\n for (const handler of this.handlers.widget) {\n handler({ widgetType: event.widget_type, data: event.data });\n }\n break;\n case 'error':\n for (const handler of this.handlers.error) {\n handler({ message: event.message });\n }\n break;\n case 'init':\n case 'done':\n // Init handled by ChatClient, done triggers after loop\n break;\n default:\n break;\n }\n }\n}\n","/**\n * @license\n * Copyright 2025 Amodal Labs, Inc.\n * SPDX-License-Identifier: MIT\n */\n\nimport { TypedEventEmitter } from './EventEmitter';\nimport { ChatStream } from './ChatStream';\nimport type { ChatResponse } from './ChatStream';\nimport { createSession, streamChat } from './chat-api';\nimport type { ChatUser, ChatMessage, AssistantTextMessage, ToolCallInfo, KBProposalInfo } from '../types';\nimport { WidgetEventBus } from '../events/event-bus';\nimport type { WidgetEvent, EntityExtractor, ToolExecutedEvent, SkillActivatedEvent, WidgetRenderedEvent, KBProposalEvent } from '../events/types';\n\n/**\n * Configuration for the ChatClient.\n */\nexport interface ChatClientConfig {\n serverUrl: string;\n user: ChatUser;\n /** Bearer token (API key or JWT) for authenticated requests. */\n token?: string;\n /** Custom entity extractors. If provided, replaces the default extractor. */\n entityExtractors?: EntityExtractor[];\n}\n\n/**\n * Events emitted by the ChatClient.\n */\nexport interface ClientEvents {\n connected: undefined;\n disconnected: undefined;\n reconnecting: number;\n message: ChatMessage;\n streaming_start: undefined;\n streaming_end: undefined;\n error: Error;\n tool_executed: ToolExecutedEvent;\n skill_activated: SkillActivatedEvent;\n widget_rendered: WidgetRenderedEvent;\n kb_proposal_received: KBProposalEvent;\n entity_referenced: WidgetEvent;\n}\n\nlet msgCounter = 0;\nfunction makeId(): string {\n msgCounter++;\n return `msg-${Date.now()}-${String(msgCounter)}`;\n}\n\n/**\n * Headless chat client for framework-agnostic integrations.\n * Manages session lifecycle, message history, and SSE streaming.\n */\nexport class ChatClient extends TypedEventEmitter<ClientEvents> {\n private config: ChatClientConfig;\n private sessionId: string | null = null;\n private _messages: ChatMessage[] = [];\n private _isConnected = false;\n private _isStreaming = false;\n private connectAttempt = 0;\n private maxReconnectAttempts = 3;\n private _eventBus: WidgetEventBus;\n\n constructor(config: ChatClientConfig) {\n super();\n this.config = config;\n this._eventBus = new WidgetEventBus();\n if (config.entityExtractors) {\n this._eventBus.setExtractors(config.entityExtractors);\n }\n // Forward entity_referenced events from bus to client events\n this._eventBus.on('entity_referenced', (e) => {\n this.emit('entity_referenced', e);\n });\n }\n\n /** The widget event bus. Subscribe to agent-driven events here. */\n get events(): WidgetEventBus {\n return this._eventBus;\n }\n\n /** Whether the client has an active session. */\n get isConnected(): boolean {\n return this._isConnected;\n }\n\n /** Whether a response is currently streaming. */\n get isStreaming(): boolean {\n return this._isStreaming;\n }\n\n /** Current session ID, or null if not connected. */\n getSessionId(): string | null {\n return this.sessionId;\n }\n\n /** Readonly message history. */\n get messages(): readonly ChatMessage[] {\n return this._messages;\n }\n\n /** Establish a session with the server. */\n async connect(): Promise<void> {\n try {\n const session = await createSession(\n this.config.serverUrl,\n this.config.user,\n this.config.token,\n );\n this.sessionId = session.session_id;\n this._isConnected = true;\n this.connectAttempt = 0;\n this.emit('connected', undefined);\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n this.emit('error', error);\n throw error;\n }\n }\n\n /** Disconnect and clean up. */\n async disconnect(): Promise<void> {\n this.sessionId = null;\n this._isConnected = false;\n this._isStreaming = false;\n this.emit('disconnected', undefined);\n }\n\n /** Clear message history. */\n clearHistory(): void {\n this._messages = [];\n }\n\n /**\n * Send a message and wait for the full response.\n * Auto-connects if not already connected.\n */\n async send(text: string): Promise<ChatResponse> {\n if (!this._isConnected) {\n await this.connect();\n }\n\n // Add user message\n const userMsg: ChatMessage = {\n type: 'user',\n id: makeId(),\n text,\n timestamp: new Date().toISOString(),\n };\n this._messages.push(userMsg);\n this.emit('message', userMsg);\n\n // Create assistant message placeholder\n const assistantMsg: AssistantTextMessage = {\n type: 'assistant_text',\n id: makeId(),\n text: '',\n toolCalls: [],\n confirmations: [],\n skillActivations: [],\n kbProposals: [],\n widgets: [],\n contentBlocks: [],\n timestamp: new Date().toISOString(),\n };\n this._messages.push(assistantMsg);\n this.emit('message', assistantMsg);\n\n this._isStreaming = true;\n this.emit('streaming_start', undefined);\n\n try {\n const response = await this.streamInternal(text, assistantMsg);\n return response;\n } catch (err) {\n // Try reconnection\n if (this.connectAttempt < this.maxReconnectAttempts) {\n return await this.reconnectAndRetry(text, assistantMsg);\n }\n throw err;\n } finally {\n this._isStreaming = false;\n this.emit('streaming_end', undefined);\n }\n }\n\n /**\n * Stream a message, returning a ChatStream handle for event-based consumption.\n */\n stream(text: string): ChatStream {\n // Add user message\n const userMsg: ChatMessage = {\n type: 'user',\n id: makeId(),\n text,\n timestamp: new Date().toISOString(),\n };\n this._messages.push(userMsg);\n this.emit('message', userMsg);\n\n this._isStreaming = true;\n this.emit('streaming_start', undefined);\n\n const chatStream = new ChatStream(this.config.serverUrl, {\n message: text,\n session_id: this.sessionId ?? undefined,\n role: this.config.user.role,\n }, this.config.token);\n\n // Track streaming state\n chatStream.on('done', (response) => {\n // Add assistant message to history\n const assistantMsg: AssistantTextMessage = {\n type: 'assistant_text',\n id: makeId(),\n text: response.text,\n toolCalls: response.toolCalls,\n confirmations: [],\n skillActivations: response.skillsUsed,\n kbProposals: response.kbProposals,\n widgets: [],\n contentBlocks: [],\n timestamp: new Date().toISOString(),\n };\n this._messages.push(assistantMsg);\n this.emit('message', assistantMsg);\n this._isStreaming = false;\n this.emit('streaming_end', undefined);\n });\n\n chatStream.on('error', (err) => {\n this._isStreaming = false;\n this.emit('streaming_end', undefined);\n this.emit('error', new Error(err.message));\n });\n\n return chatStream;\n }\n\n private async streamInternal(\n text: string,\n assistantMsg: AssistantTextMessage,\n ): Promise<ChatResponse> {\n const response: ChatResponse = {\n text: '',\n toolCalls: [],\n skillsUsed: [],\n kbProposals: [],\n };\n\n const pendingToolCalls = new Map<string, { toolName: string; parameters: Record<string, unknown> }>();\n\n const stream = streamChat(\n this.config.serverUrl,\n {\n message: text,\n session_id: this.sessionId ?? undefined,\n role: this.config.user.role,\n },\n undefined,\n this.config.token,\n );\n\n for await (const event of stream) {\n switch (event.type) {\n case 'init':\n this.sessionId = event.session_id;\n break;\n case 'text_delta':\n response.text += event.content;\n assistantMsg.text += event.content;\n break;\n case 'tool_call_start': {\n const tc: ToolCallInfo = {\n toolId: event.tool_id,\n toolName: event.tool_name,\n parameters: event.parameters,\n status: 'running',\n };\n response.toolCalls.push(tc);\n assistantMsg.toolCalls = [...assistantMsg.toolCalls, tc];\n pendingToolCalls.set(event.tool_id, {\n toolName: event.tool_name,\n parameters: event.parameters,\n });\n break;\n }\n case 'tool_call_result': {\n const existing = response.toolCalls.find((t) => t.toolId === event.tool_id);\n if (existing) {\n existing.status = event.status;\n existing.result = event.result;\n existing.duration_ms = event.duration_ms;\n existing.error = event.error;\n }\n assistantMsg.toolCalls = assistantMsg.toolCalls.map((t) =>\n t.toolId === event.tool_id\n ? { ...t, status: event.status, result: event.result, duration_ms: event.duration_ms, error: event.error }\n : t,\n );\n\n const pending = pendingToolCalls.get(event.tool_id);\n pendingToolCalls.delete(event.tool_id);\n const toolEvent: ToolExecutedEvent = {\n type: 'tool_executed',\n toolName: pending?.toolName ?? '',\n toolId: event.tool_id,\n parameters: pending?.parameters ?? {},\n status: event.status,\n result: event.result,\n duration_ms: event.duration_ms,\n error: event.error,\n timestamp: event.timestamp,\n };\n this._eventBus.processEvent(toolEvent);\n this.emit('tool_executed', toolEvent);\n break;\n }\n case 'skill_activated': {\n response.skillsUsed.push(event.skill);\n assistantMsg.skillActivations = [...assistantMsg.skillActivations, event.skill];\n const skillEvent: SkillActivatedEvent = {\n type: 'skill_activated',\n skill: event.skill,\n timestamp: event.timestamp,\n };\n this._eventBus.processEvent(skillEvent);\n this.emit('skill_activated', skillEvent);\n break;\n }\n case 'kb_proposal': {\n const proposal: KBProposalInfo = {\n scope: event.scope,\n title: event.title,\n reasoning: event.reasoning,\n };\n response.kbProposals.push(proposal);\n assistantMsg.kbProposals = [...assistantMsg.kbProposals, proposal];\n const kbEvent: KBProposalEvent = {\n type: 'kb_proposal',\n proposal,\n timestamp: event.timestamp,\n };\n this._eventBus.processEvent(kbEvent);\n this.emit('kb_proposal_received', kbEvent);\n break;\n }\n case 'widget': {\n const widgetEvent: WidgetRenderedEvent = {\n type: 'widget_rendered',\n widgetType: event.widget_type,\n data: event.data,\n timestamp: event.timestamp,\n };\n this._eventBus.processEvent(widgetEvent);\n this.emit('widget_rendered', widgetEvent);\n break;\n }\n case 'error':\n throw new Error(event.message);\n case 'done':\n break;\n default:\n break;\n }\n }\n\n return response;\n }\n\n private async reconnectAndRetry(\n text: string,\n assistantMsg: AssistantTextMessage,\n ): Promise<ChatResponse> {\n this.connectAttempt++;\n this.emit('reconnecting', this.connectAttempt);\n\n // Exponential backoff: 100ms, 200ms, 400ms\n const delay = 100 * Math.pow(2, this.connectAttempt - 1);\n await new Promise((resolve) => setTimeout(resolve, delay));\n\n try {\n await this.connect();\n return await this.streamInternal(text, assistantMsg);\n } catch (err) {\n if (this.connectAttempt < this.maxReconnectAttempts) {\n return this.reconnectAndRetry(text, assistantMsg);\n }\n throw err;\n }\n }\n}\n"],"names":["RuntimeClient","options","__publicField","headers","token","message","url","body","streamSSE","prompt","response","taskId","signal","streamSSEGet","authH","storeName","params","qs","key","ChatStream","serverUrl","request","event","handler","stream","streamChat","err","toolName","tc","t","proposal","msgCounter","makeId","ChatClient","TypedEventEmitter","config","WidgetEventBus","session","createSession","error","text","userMsg","assistantMsg","chatStream","pendingToolCalls","existing","pending","toolEvent","skillEvent","kbEvent","widgetEvent","delay","resolve"],"mappings":"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"}
|
package/dist/provider.d.ts
CHANGED
|
@@ -3,21 +3,18 @@ import { RuntimeClient } from './client/runtime-client';
|
|
|
3
3
|
export interface AmodalProviderProps {
|
|
4
4
|
/** Base URL of the Amodal runtime server (e.g., "http://localhost:3001"). */
|
|
5
5
|
runtimeUrl: string;
|
|
6
|
-
/**
|
|
7
|
-
appId: string;
|
|
8
|
-
/** Optional async token getter for auth headers. */
|
|
6
|
+
/** Optional token getter for auth (hosted mode). */
|
|
9
7
|
getToken?: () => string | Promise<string> | null | undefined;
|
|
10
8
|
children: ReactNode;
|
|
11
9
|
}
|
|
12
10
|
interface AmodalContextValue {
|
|
13
11
|
client: RuntimeClient;
|
|
14
12
|
runtimeUrl: string;
|
|
15
|
-
appId: string;
|
|
16
13
|
}
|
|
17
14
|
/**
|
|
18
15
|
* Provides a RuntimeClient to all child hooks and components.
|
|
19
16
|
*/
|
|
20
|
-
export declare function AmodalProvider({ runtimeUrl,
|
|
17
|
+
export declare function AmodalProvider({ runtimeUrl, getToken, children }: AmodalProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
21
18
|
/**
|
|
22
19
|
* Access the RuntimeClient and config from the nearest AmodalProvider.
|
|
23
20
|
* Throws if called outside of an AmodalProvider.
|
package/dist/provider.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAExD,MAAM,WAAW,mBAAmB;IAClC,6EAA6E;IAC7E,UAAU,EAAE,MAAM,CAAC;IACnB,
|
|
1
|
+
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAExD,MAAM,WAAW,mBAAmB;IAClC,6EAA6E;IAC7E,UAAU,EAAE,MAAM,CAAC;IACnB,oDAAoD;IACpD,QAAQ,CAAC,EAAE,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,IAAI,GAAG,SAAS,CAAC;IAC7D,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,UAAU,kBAAkB;IAC1B,MAAM,EAAE,aAAa,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;CACpB;AAID;;GAEG;AACH,wBAAgB,cAAc,CAAC,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,mBAAmB,2CAYrF;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,kBAAkB,CAMrD"}
|
package/dist/react.css
CHANGED
|
@@ -2,4 +2,4 @@
|
|
|
2
2
|
* @license
|
|
3
3
|
* Copyright 2025 Amodal Labs, Inc.
|
|
4
4
|
* SPDX-License-Identifier: MIT
|
|
5
|
-
*/.pcw-widget{--pcw-primary: #1e40af;--pcw-bg: #ffffff;--pcw-font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;--pcw-font-size: 14px;--pcw-radius: 8px;--pcw-user-bubble: #1e40af;--pcw-agent-bubble: #f3f4f6;--pcw-tool-call-bg: #f9fafb;--pcw-text: #111827;--pcw-text-muted: #6b7280;--pcw-border: #e5e7eb;--pcw-shadow: 0 4px 6px -1px rgba(0, 0, 0, .1), 0 2px 4px -1px rgba(0, 0, 0, .06);font-family:var(--pcw-font);font-size:var(--pcw-font-size);color:var(--pcw-text);box-sizing:border-box;line-height:1.5}.pcw-widget *,.pcw-widget *:before,.pcw-widget *:after{box-sizing:border-box}.pcw-widget--inline{display:flex;flex-direction:column;height:100%;width:100%;background:var(--pcw-bg);border-radius:var(--pcw-radius);overflow:hidden}.pcw-widget--right{position:fixed;top:0;right:0;width:400px;height:100vh;background:var(--pcw-bg);box-shadow:var(--pcw-shadow);z-index:9999;display:flex;flex-direction:column}.pcw-widget--floating{position:fixed;bottom:24px;right:24px;width:400px;height:600px;max-height:calc(100vh - 48px);background:var(--pcw-bg);border-radius:var(--pcw-radius);box-shadow:var(--pcw-shadow);z-index:9999;display:flex;flex-direction:column;overflow:hidden}.pcw-widget--bottom{position:fixed;bottom:0;left:0;right:0;height:400px;background:var(--pcw-bg);box-shadow:0 -2px 10px #0000001a;z-index:9999;display:flex;flex-direction:column}.pcw-header{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;border-bottom:1px solid var(--pcw-border);background:var(--pcw-bg);flex-shrink:0}.pcw-header__title{font-weight:600;font-size:15px;margin:0}.pcw-header__close{background:none;border:none;cursor:pointer;padding:4px;color:var(--pcw-text-muted);font-size:18px;line-height:1}.pcw-header__close:hover{color:var(--pcw-text)}.pcw-messages{flex:1;overflow-y:auto;padding:16px;display:flex;flex-direction:column;gap:12px}.pcw-messages--empty{flex:1;display:flex;align-items:center;justify-content:center;color:var(--pcw-text-muted);padding:16px}.pcw-bubble{max-width:80%;padding:8px 12px;border-radius:var(--pcw-radius);word-wrap:break-word;white-space:pre-wrap}.pcw-bubble--user{align-self:flex-end;background:var(--pcw-user-bubble);color:#fff}.pcw-bubble--assistant{align-self:flex-start;background:var(--pcw-agent-bubble);color:var(--pcw-text)}.pcw-bubble__text{margin:0;font-size:var(--pcw-font-size);line-height:1.5}.pcw-bubble__extras{display:flex;flex-direction:column;gap:8px;margin-top:8px}.pcw-tool-call{background:var(--pcw-tool-call-bg);border:1px solid var(--pcw-border);border-radius:6px;padding:8px;font-size:12px}.pcw-tool-call__header{display:flex;align-items:center;gap:6px;cursor:pointer;background:none;border:none;width:100%;text-align:left;padding:0;font-family:inherit;font-size:inherit;color:var(--pcw-text)}.pcw-tool-call__chevron{flex-shrink:0;font-size:10px;color:var(--pcw-text-muted)}.pcw-tool-call__name{font-family:monospace;font-weight:500}.pcw-tool-call__status{margin-left:auto;padding:1px 6px;border-radius:4px;font-size:10px;font-weight:500;text-transform:uppercase}.pcw-tool-call__status--running{background:#dbeafe;color:#1e40af}.pcw-tool-call__status--success{background:#dcfce7;color:#166534}.pcw-tool-call__status--error{background:#fee2e2;color:#991b1b}.pcw-tool-call__details{margin-top:8px;background:var(--pcw-agent-bubble);border-radius:4px;padding:8px;overflow-x:auto;font-family:monospace;font-size:11px;white-space:pre-wrap}.pcw-tool-call__subagent{padding:2px 0 2px 12px;border-left:2px solid var(--pcw-border, #e5e7eb);margin:4px 0 4px 8px}.pcw-subagent-row{font-size:12px;color:var(--pcw-text-muted, #6b7280)}.pcw-subagent-row__header{display:flex;align-items:center;gap:5px;width:100%;padding:3px 4px;border:none;border-radius:3px;background:none;cursor:pointer;font:inherit;color:inherit;text-align:left}.pcw-subagent-row__header:hover{background:var(--pcw-bg-hover, rgba(0, 0, 0, .04))}.pcw-subagent-row__header--static{cursor:default}.pcw-subagent-row__header--static:hover{background:none}.pcw-subagent-row__chevron{font-size:8px;width:10px;flex-shrink:0;opacity:.5}.pcw-subagent-row__icon{width:14px;flex-shrink:0;text-align:center;color:#16a34a}.pcw-subagent-row__icon--error{color:#dc2626}.pcw-subagent-row__name{font-family:var(--pcw-font-mono, ui-monospace, monospace);font-weight:500}.pcw-subagent-row__detail{margin:2px 0 4px 29px}.pcw-subagent-row__result,.pcw-subagent-row__error,.pcw-subagent-row__args{margin:0;padding:6px 8px;border-radius:4px;background:var(--pcw-bg-code, #f3f4f6);font-family:var(--pcw-font-mono, ui-monospace, monospace);font-size:11px;line-height:1.5;white-space:pre-wrap;word-break:break-word;max-height:200px;overflow-y:auto}.pcw-subagent-row__error{color:#dc2626;background:#fef2f2}.pcw-subagent-row__args{margin-top:4px;opacity:.8}.pcw-dispatch-args{margin:6px 0 2px;display:flex;flex-direction:column;gap:3px}.pcw-dispatch-args__row{display:flex;gap:6px;align-items:baseline;line-height:1.4}.pcw-dispatch-args__label{flex-shrink:0;width:56px;font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.03em;color:var(--pcw-text-muted, #6b7280)}.pcw-dispatch-args__value{font-size:12px;color:var(--pcw-text, #111827);line-height:1.4}.pcw-dispatch-args__value--mono{font-family:var(--pcw-font-mono, ui-monospace, monospace);font-weight:500}.pcw-dispatch-args__tags{display:flex;flex-wrap:wrap;gap:3px}.pcw-dispatch-args__tag{padding:0 5px;border-radius:3px;font-size:11px;font-family:var(--pcw-font-mono, ui-monospace, monospace);background:var(--pcw-bg-code, #f3f4f6);color:var(--pcw-text-muted, #6b7280)}.pcw-dispatch-details{margin-top:6px;border-top:1px solid var(--pcw-border, #e5e7eb);padding-top:4px}.pcw-dispatch-details__toggle{display:flex;align-items:center;gap:5px;background:none;border:none;padding:3px 0;cursor:pointer;font:inherit;font-size:11px;font-weight:500;color:var(--pcw-text-muted, #6b7280)}.pcw-dispatch-details__toggle:hover{color:var(--pcw-text, #111827)}.pcw-dispatch-details__count{margin-left:4px;font-weight:400;opacity:.7}.pcw-dispatch-details__body{margin-top:4px}.pcw-tool-call__subagent-summary{padding:8px 10px;margin:4px 0;font-size:12px;line-height:1.5;color:var(--pcw-text, #111827);background:var(--pcw-agent-bubble, #f3f4f6);border-radius:6px;max-height:400px;overflow-y:auto}.pcw-formatted-text{white-space:normal}.pcw-formatted-text p{margin:0 0 4px}.pcw-formatted-text p:last-child{margin-bottom:0}.pcw-md-h1,.pcw-md-h2,.pcw-md-h3,.pcw-md-h4{margin:10px 0 4px;line-height:1.3}.pcw-md-h1{font-size:15px;font-weight:700}.pcw-md-h2{font-size:14px;font-weight:600}.pcw-md-h3{font-size:13px;font-weight:600}.pcw-md-h4{font-size:12px;font-weight:600}.pcw-md-h1:first-child,.pcw-md-h2:first-child,.pcw-md-h3:first-child,.pcw-md-h4:first-child{margin-top:0}.pcw-md-list{margin:2px 0 4px;padding-left:20px}.pcw-md-list li{margin:1px 0}.pcw-md-list:last-child{margin-bottom:0}.pcw-md-code{padding:1px 4px;border-radius:3px;font-family:var(--pcw-font-mono, ui-monospace, monospace);font-size:.9em;background:var(--pcw-bg-code, rgba(0, 0, 0, .06))}.pcw-md-codeblock{margin:4px 0;padding:8px;border-radius:4px;background:var(--pcw-bg-code, #f3f4f6);font-family:var(--pcw-font-mono, ui-monospace, monospace);font-size:11px;line-height:1.5;overflow-x:auto;white-space:pre}.pcw-md-codeblock code{background:none;padding:0}.pcw-formatted-text strong{font-weight:600}.pcw-formatted-text a{color:var(--pcw-primary, #1e40af);text-decoration:underline}.pcw-dispatch-streaming{border-top:1px solid var(--pcw-border, #e5e7eb);padding:8px 12px;max-height:200px;overflow-y:auto}.pcw-subagent-inline-tool{display:flex;align-items:center;gap:5px;padding:3px 4px;font-size:12px;color:var(--pcw-text-muted, #6b7280)}.pcw-subagent-row__icon--running{color:#2563eb}.pcw-dispatch-inline-text{padding:2px 4px;font-size:12px;color:var(--pcw-text-muted, #6b7280)}.pcw-tool-call__header--static{cursor:default}.pcw-tool-call__error{margin-top:4px;color:#dc2626;font-size:11px}.pcw-tool-call__duration{color:var(--pcw-text-muted);font-size:10px;margin-left:4px}.pcw-kb-proposal{background:#fffbeb;border:1px solid #fbbf24;border-radius:6px;padding:8px 12px;font-size:12px}.pcw-kb-proposal__header{display:flex;align-items:center;gap:6px;margin-bottom:4px}.pcw-kb-proposal__icon{font-size:14px}.pcw-kb-proposal__title{font-weight:600;font-size:13px}.pcw-kb-proposal__scope{padding:1px 6px;border-radius:4px;font-size:10px;font-weight:500;text-transform:uppercase;background:#fef3c7;color:#92400e;margin-left:auto}.pcw-kb-proposal__reasoning{color:var(--pcw-text-muted);font-size:12px;margin:0}.pcw-skill-pill{display:inline-flex;align-items:center;gap:4px;padding:2px 8px;border-radius:12px;background:#ede9fe;color:#5b21b6;font-size:11px;font-weight:500;align-self:flex-start}.pcw-streaming{display:flex;align-items:center;gap:4px;padding:8px 16px;align-self:flex-start}.pcw-streaming__dot{width:6px;height:6px;border-radius:50%;background:var(--pcw-text-muted);animation:pcw-bounce 1.4s ease-in-out infinite}.pcw-streaming__dot:nth-child(1){animation-delay:-.32s}.pcw-streaming__dot:nth-child(2){animation-delay:-.16s}@keyframes pcw-bounce{0%,80%,to{transform:scale(0)}40%{transform:scale(1)}}.pcw-input{display:flex;align-items:flex-end;gap:8px;padding:12px 16px;border-top:1px solid var(--pcw-border);background:var(--pcw-bg);flex-shrink:0}.pcw-input__textarea{flex:1;min-height:40px;max-height:120px;padding:8px 12px;border:1px solid var(--pcw-border);border-radius:6px;font-family:var(--pcw-font);font-size:var(--pcw-font-size);resize:none;outline:none;line-height:1.5;color:var(--pcw-text);background:var(--pcw-bg)}.pcw-input__textarea:focus{border-color:var(--pcw-primary);box-shadow:0 0 0 2px #1e40af1a}.pcw-input__textarea::placeholder{color:var(--pcw-text-muted)}.pcw-input__textarea:disabled{opacity:.5;cursor:not-allowed}.pcw-input__send{display:flex;align-items:center;justify-content:center;width:36px;height:36px;border:none;border-radius:6px;background:var(--pcw-primary);color:#fff;cursor:pointer;flex-shrink:0;transition:opacity .15s}.pcw-input__send:hover:not(:disabled){opacity:.9}.pcw-input__send:disabled{opacity:.4;cursor:not-allowed}.pcw-input__send svg{width:16px;height:16px}.pcw-input__stop{background:var(--pcw-danger, #dc2626)}.pcw-input__stop:hover{opacity:.9}.pcw-toggle{position:fixed;bottom:24px;right:24px;width:56px;height:56px;border-radius:50%;background:var(--pcw-primary);color:#fff;border:none;cursor:pointer;box-shadow:var(--pcw-shadow);display:flex;align-items:center;justify-content:center;z-index:9998;transition:transform .15s}.pcw-toggle:hover{transform:scale(1.05)}.pcw-toggle svg{width:24px;height:24px}.pcw-error{padding:8px 16px;background:#fee2e2;color:#991b1b;font-size:12px;border-top:1px solid #fecaca}.pcw-widget-card{border:1px solid var(--pcw-border);border-radius:6px;padding:10px;margin:4px 0;font-size:12px;background:var(--pcw-bg)}.pcw-widget-card--generic{background:var(--pcw-tool-call-bg)}.pcw-widget-card__header{display:flex;align-items:center;gap:6px;margin-bottom:6px}.pcw-widget-card__type{font-family:monospace;font-size:11px;color:var(--pcw-text-muted)}.pcw-widget-card__json{margin:0;font-size:11px;font-family:monospace;white-space:pre-wrap;overflow-x:auto;max-height:200px;overflow-y:auto;background:var(--pcw-agent-bubble);padding:6px;border-radius:4px}.pcw-entity-card__header{display:flex;align-items:baseline;gap:8px;margin-bottom:4px}.pcw-entity-card__mac{font-family:monospace;font-weight:600;font-size:13px}.pcw-entity-card__mfr{color:var(--pcw-text-muted);font-size:12px}.pcw-entity-card__protocols{display:flex;flex-wrap:wrap;gap:4px;margin-bottom:6px}.pcw-entity-card__protocol-badge{display:inline-block;padding:1px 6px;border-radius:4px;background:#dbeafe;color:#1e40af;font-size:10px;font-weight:500}.pcw-entity-card__zone{font-size:11px;color:var(--pcw-text-muted);margin-bottom:6px}.pcw-entity-card__factors{font-size:11px;margin:6px 0;padding:4px 6px;background:var(--pcw-agent-bubble);border-radius:4px}.pcw-entity-card__factor{display:flex;justify-content:space-between;padding:1px 0}.pcw-entity-card__meta{display:flex;gap:12px;font-size:11px;color:var(--pcw-text-muted);margin:4px 0}.pcw-entity-card__actions{display:flex;gap:6px;margin-top:6px}.pcw-entity-card__btn{padding:4px 10px;border:1px solid var(--pcw-primary);border-radius:4px;background:var(--pcw-primary);color:#fff;font-size:11px;font-weight:500;cursor:pointer;font-family:inherit}.pcw-entity-card__btn:hover{opacity:.9}.pcw-entity-card__btn--secondary{background:transparent;color:var(--pcw-primary)}.pcw-entity-card__btn--secondary:hover{background:#1e40af0d}.pcw-score-bar{margin:4px 0}.pcw-score-bar__label{font-size:11px;font-weight:500;margin-bottom:2px}.pcw-score-bar__track{height:6px;background:#e5e7eb;border-radius:3px;overflow:hidden}.pcw-score-bar__fill{height:100%;border-radius:3px;background:linear-gradient(to right,#10b981,#f59e0b,#ef4444);transition:width .3s ease}.pcw-alert-card__header{display:flex;align-items:center;gap:8px;margin-bottom:6px}.pcw-alert-card__severity{padding:2px 8px;border-radius:4px;font-size:10px;font-weight:600;text-transform:uppercase}.pcw-alert-card__severity--low{background:#f3f4f6;color:#374151}.pcw-alert-card__severity--medium{background:#fef3c7;color:#92400e}.pcw-alert-card__severity--high{background:#fed7aa;color:#9a3412}.pcw-alert-card__severity--critical{background:#fee2e2;color:#991b1b}.pcw-alert-card__type{font-weight:500}.pcw-alert-card__zone{color:var(--pcw-text-muted);font-size:11px;margin-left:auto}.pcw-alert-card__description{margin:0 0 6px;font-size:12px;line-height:1.4}.pcw-alert-card__devices{display:flex;flex-wrap:wrap;gap:4px;margin-bottom:4px}.pcw-alert-card__device-link{font-family:monospace;font-size:11px;color:var(--pcw-primary);background:none;border:none;cursor:pointer;padding:1px 4px;text-decoration:underline}.pcw-alert-card__device-link:hover{opacity:.7}.pcw-alert-card__protocols{display:flex;gap:4px;margin-bottom:4px}.pcw-alert-card__time{font-size:10px;color:var(--pcw-text-muted)}.pcw-timeline__label{font-weight:500;font-size:12px;margin-bottom:8px}.pcw-timeline__events{position:relative;padding-left:16px}.pcw-timeline__events:before{content:"";position:absolute;left:5px;top:0;bottom:0;width:2px;background:var(--pcw-border)}.pcw-timeline__event{position:relative;display:flex;align-items:flex-start;gap:8px;padding:4px 0}.pcw-timeline__marker{width:10px;height:10px;border-radius:50%;flex-shrink:0;margin-top:2px;position:relative;z-index:1;margin-left:-11px}.pcw-timeline__content{display:flex;align-items:baseline;gap:6px;flex-wrap:wrap}.pcw-timeline__time{font-size:10px;color:var(--pcw-text-muted);font-family:monospace}.pcw-timeline__event-label{font-size:12px}.pcw-comparison__title{font-weight:500;font-size:12px;margin-bottom:8px}.pcw-comparison__grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:8px}.pcw-comparison__item{border:1px solid var(--pcw-border);border-radius:4px;padding:8px;display:flex;flex-direction:column;gap:2px}.pcw-comparison__mac{font-family:monospace;font-weight:600;font-size:11px}.pcw-comparison__detail{font-size:11px;color:var(--pcw-text-muted)}.pcw-comparison__score{font-size:11px;font-weight:500}.pcw-data-table__title{font-weight:500;font-size:12px;margin-bottom:6px}.pcw-data-table__scroll{overflow-x:auto}.pcw-data-table__table{width:100%;border-collapse:collapse;font-size:11px}.pcw-data-table__table th,.pcw-data-table__table td{padding:4px 8px;text-align:left;border-bottom:1px solid var(--pcw-border)}.pcw-data-table__table th{font-weight:600;background:var(--pcw-agent-bubble);white-space:nowrap}.pcw-data-table__sortable{cursor:pointer;-webkit-user-select:none;user-select:none}.pcw-data-table__sortable:hover{background:#e5e7eb}.pcw-entity-list__title{font-weight:500;font-size:12px;margin-bottom:6px}.pcw-entity-list__sort{display:flex;align-items:center;gap:4px;font-size:10px;color:var(--pcw-text-muted);margin-bottom:6px}.pcw-entity-list__sort-btn{padding:1px 6px;border:1px solid var(--pcw-border);border-radius:3px;background:transparent;font-size:10px;cursor:pointer;font-family:inherit;color:var(--pcw-text-muted)}.pcw-entity-list__sort-btn--active{background:var(--pcw-primary);color:#fff;border-color:var(--pcw-primary)}.pcw-entity-list__row{cursor:pointer}.pcw-entity-list__row:hover{background:var(--pcw-agent-bubble)}.pcw-entity-list__row--expanded{background:#eff6ff}.pcw-entity-list__mac{font-family:monospace;font-size:11px}.pcw-entity-list__detail{padding:6px 8px;display:flex;gap:6px}.pcw-entity-list__more{text-align:center;font-size:11px;color:var(--pcw-text-muted);padding:4px}.pcw-scope-map__label{font-weight:500;font-size:12px;margin-bottom:6px}.pcw-scope-map__svg{width:100%;max-width:280px}.pcw-scope-map__zone{fill:#f3f4f6;stroke:#d1d5db;stroke-width:1}.pcw-scope-map__zone--highlight{fill:#fee2e2;stroke:#ef4444;stroke-width:2}.pcw-scope-map__zone-label{font-size:9px;font-weight:600;fill:#374151}.pcw-scope-map__zone-name{font-size:7px;fill:#6b7280}.pcw-scope-map__devices{display:flex;flex-wrap:wrap;gap:4px;margin-top:6px}.pcw-scope-map__device-badge{font-family:monospace;font-size:10px;padding:1px 4px;background:#fee2e2;border-radius:3px;color:#991b1b}.pcw-score-breakdown__label{font-weight:500;font-size:12px;margin-bottom:6px}.pcw-score-breakdown__factors{margin-top:8px;display:flex;flex-direction:column;gap:6px}.pcw-score-breakdown__factor{font-size:11px}.pcw-score-breakdown__factor-header{display:flex;justify-content:space-between;margin-bottom:2px}.pcw-score-breakdown__factor-name{text-transform:capitalize}.pcw-score-breakdown__factor-value{font-weight:600;color:var(--pcw-primary)}.pcw-score-breakdown__factor-bar{height:4px;background:#e5e7eb;border-radius:2px;overflow:hidden}.pcw-score-breakdown__factor-fill{height:100%;background:var(--pcw-primary);border-radius:2px;transition:width .3s ease}.pcw-score-breakdown__factor-desc{font-size:10px;color:var(--pcw-text-muted);margin-top:2px}.pcw-status-board__title{font-weight:500;font-size:12px;margin-bottom:6px}.pcw-status-board__items{display:flex;flex-direction:column;gap:4px}.pcw-status-board__item{padding:6px 8px;border-radius:4px;border-left:3px solid transparent}.pcw-status-board__item:hover{background:var(--pcw-agent-bubble)}.pcw-status-board__item--critical{border-left-color:#dc2626}.pcw-status-board__item--high{border-left-color:#ea580c}.pcw-status-board__item--medium{border-left-color:#ca8a04}.pcw-status-board__item--low{border-left-color:#2563eb}.pcw-status-board__item-header{display:flex;align-items:baseline;gap:8px;font-size:12px}.pcw-status-board__severity{font-size:9px;font-weight:700;padding:1px 4px;border-radius:3px}.pcw-status-board__severity--critical{background:#fee2e2;color:#dc2626}.pcw-status-board__severity--high{background:#ffedd5;color:#ea580c}.pcw-status-board__severity--medium{background:#fef9c3;color:#ca8a04}.pcw-status-board__severity--low{background:#dbeafe;color:#2563eb}.pcw-status-board__item-label{font-weight:500;flex:1}.pcw-status-board__item-status{font-size:10px;color:var(--pcw-text-muted)}.pcw-status-board__item-desc{font-size:11px;color:var(--pcw-text-muted);margin-top:2px}.pcw-widget-card--credential-input{background:var(--pcw-bg)}.pcw-credential-input__title{font-weight:600;font-size:13px;margin-bottom:10px}.pcw-credential-input__field{display:flex;flex-direction:column;gap:2px;margin-bottom:8px}.pcw-credential-input__label{font-size:11px;font-weight:500;color:var(--pcw-text)}.pcw-credential-input__input{padding:6px 8px;border:1px solid var(--pcw-border);border-radius:4px;font-family:var(--pcw-font);font-size:12px;color:var(--pcw-text);background:var(--pcw-bg);outline:none}.pcw-credential-input__input:focus{border-color:var(--pcw-primary);box-shadow:0 0 0 2px #1e40af1a}.pcw-credential-input__input:disabled{opacity:.5;cursor:not-allowed}.pcw-credential-input__submit{display:block;width:100%;padding:6px 12px;margin-top:4px;border:none;border-radius:4px;background:var(--pcw-primary);color:#fff;font-family:inherit;font-size:12px;font-weight:500;cursor:pointer;transition:opacity .15s}.pcw-credential-input__submit:hover:not(:disabled){opacity:.9}.pcw-credential-input__submit:disabled{opacity:.5;cursor:not-allowed}.pcw-credential-input__status{font-size:12px;padding:6px 8px;border-radius:4px;margin-bottom:6px}.pcw-credential-input__status--success{background:#dcfce7;color:#166534}.pcw-credential-input__status--error{background:#fee2e2;color:#991b1b}.pcw-widget-card--document-preview{background:var(--pcw-bg)}.pcw-document-preview__header{display:flex;align-items:center;gap:6px;margin-bottom:8px;flex-wrap:wrap}.pcw-document-preview__title{font-weight:600;font-size:13px}.pcw-document-preview__badge{padding:1px 6px;border-radius:4px;font-size:10px;font-weight:500;text-transform:uppercase}.pcw-document-preview__badge--category{background:#dbeafe;color:#1e40af}.pcw-document-preview__badge--action{background:#fef3c7;color:#92400e}.pcw-document-preview__badge--approved{background:#dcfce7;color:#166534}.pcw-document-preview__body{margin:0 0 8px;padding:8px;background:var(--pcw-agent-bubble);border-radius:4px;font-size:11px;font-family:monospace;white-space:pre-wrap;overflow-x:auto;max-height:240px;overflow-y:auto;line-height:1.5}.pcw-document-preview__body code{font-family:inherit;font-size:inherit}.pcw-document-preview__actions{display:flex;gap:6px;margin-top:6px}.pcw-document-preview__btn{padding:4px 10px;border-radius:4px;font-size:11px;font-weight:500;cursor:pointer;font-family:inherit}.pcw-document-preview__btn--primary{border:1px solid var(--pcw-primary);background:var(--pcw-primary);color:#fff}.pcw-document-preview__btn--primary:hover{opacity:.9}.pcw-document-preview__btn--secondary{border:1px solid var(--pcw-primary);background:transparent;color:var(--pcw-primary)}.pcw-document-preview__btn--secondary:hover{background:#1e40af0d}.pcw-document-preview__editor-container{display:flex;flex-direction:column}.pcw-document-preview__editor{width:100%;padding:8px;border:1px solid var(--pcw-border);border-radius:4px;font-family:monospace;font-size:11px;color:var(--pcw-text);background:var(--pcw-bg);resize:vertical;outline:none;line-height:1.5}.pcw-document-preview__editor:focus{border-color:var(--pcw-primary);box-shadow:0 0 0 2px #1e40af1a}.pcw-ask-user{border:1px solid var(--pcw-primary);border-radius:6px;padding:10px;margin:4px 0;font-size:12px;background:var(--pcw-bg)}.pcw-ask-user--submitted{border-color:var(--pcw-border);background:var(--pcw-tool-call-bg)}.pcw-ask-user__field{display:flex;flex-direction:column;gap:4px;margin-bottom:10px}.pcw-ask-user__label{font-size:12px;font-weight:500;color:var(--pcw-text);line-height:1.4}.pcw-ask-user__header{display:inline-block;padding:1px 6px;border-radius:4px;background:#ede9fe;color:#5b21b6;font-size:10px;font-weight:600;text-transform:uppercase;margin-right:6px;vertical-align:middle}.pcw-ask-user__textarea{padding:6px 8px;border:1px solid var(--pcw-border);border-radius:4px;font-family:var(--pcw-font);font-size:12px;color:var(--pcw-text);background:var(--pcw-bg);outline:none;resize:vertical;line-height:1.5}.pcw-ask-user__textarea:focus{border-color:var(--pcw-primary);box-shadow:0 0 0 2px #1e40af1a}.pcw-ask-user__textarea:disabled{opacity:.5;cursor:not-allowed}.pcw-ask-user__yesno{display:flex;gap:6px}.pcw-ask-user__yesno-btn{padding:4px 16px;border:1px solid var(--pcw-border);border-radius:4px;background:transparent;font-family:inherit;font-size:12px;font-weight:500;cursor:pointer;color:var(--pcw-text);transition:background .1s,border-color .1s}.pcw-ask-user__yesno-btn:hover:not(:disabled){border-color:var(--pcw-primary)}.pcw-ask-user__yesno-btn--active{background:var(--pcw-primary);border-color:var(--pcw-primary);color:#fff}.pcw-ask-user__yesno-btn:disabled{opacity:.5;cursor:not-allowed}.pcw-ask-user__choices{display:flex;flex-direction:column;gap:4px}.pcw-ask-user__choice{display:flex;align-items:flex-start;gap:6px;padding:4px 6px;border-radius:4px;cursor:pointer}.pcw-ask-user__choice:hover{background:var(--pcw-agent-bubble)}.pcw-ask-user__choice input{margin-top:2px;flex-shrink:0}.pcw-ask-user__choice-label{font-weight:500;font-size:12px}.pcw-ask-user__choice-desc{font-size:11px;color:var(--pcw-text-muted);margin-left:4px}.pcw-ask-user__submit{display:block;width:100%;padding:6px 12px;border:none;border-radius:4px;background:var(--pcw-primary);color:#fff;font-family:inherit;font-size:12px;font-weight:500;cursor:pointer;transition:opacity .15s}.pcw-ask-user__submit:hover:not(:disabled){opacity:.9}.pcw-ask-user__submit:disabled{opacity:.5;cursor:not-allowed}.pcw-ask-user__summary{display:flex;flex-direction:column;gap:2px;margin-bottom:6px}.pcw-ask-user__summary:last-child{margin-bottom:0}.pcw-ask-user__summary-q{font-size:11px;color:var(--pcw-text-muted)}.pcw-ask-user__summary-a{font-size:12px;font-weight:500;color:var(--pcw-text)}.pcw-history-drawer{position:absolute;top:0;left:0;right:0;bottom:0;background:var(--pcw-bg, #ffffff);z-index:10;display:flex;flex-direction:column;overflow:hidden}.pcw-history-header{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;border-bottom:1px solid var(--pcw-border, #e5e7eb)}.pcw-history-title{font-size:14px;font-weight:600;margin:0;color:var(--pcw-text, #1a1a1a)}.pcw-history-close{background:none;border:none;cursor:pointer;padding:4px;color:var(--pcw-text-muted, #6b7280);border-radius:4px}.pcw-history-close:hover{background:var(--pcw-border, #e5e7eb)}.pcw-history-new-chat{margin:8px 16px;padding:8px 12px;background:var(--pcw-primary, #2563eb);color:#fff;border:none;border-radius:var(--pcw-radius, 8px);cursor:pointer;font-size:13px;font-weight:500;text-align:center}.pcw-history-new-chat:hover{opacity:.9}.pcw-history-filters{display:flex;flex-wrap:wrap;gap:4px;padding:4px 16px 8px}.pcw-filter-chip{font-size:11px;padding:2px 8px;border-radius:12px;border:1px solid var(--pcw-border, #e5e7eb);background:transparent;color:var(--pcw-text-muted, #6b7280);cursor:pointer}.pcw-filter-chip:hover{background:var(--pcw-border, #e5e7eb)}.pcw-filter-chip--active{background:var(--pcw-primary, #2563eb);color:#fff;border-color:var(--pcw-primary, #2563eb)}.pcw-history-list{flex:1;overflow-y:auto;padding:0 8px 8px}.pcw-history-loading,.pcw-history-empty{padding:24px 16px;text-align:center;color:var(--pcw-text-muted, #6b7280);font-size:13px}.pcw-history-item{border-radius:var(--pcw-radius, 8px);border:1px solid var(--pcw-border, #e5e7eb);margin-bottom:6px;overflow:hidden}.pcw-history-item-content{display:block;width:100%;padding:10px 12px;background:none;border:none;cursor:pointer;text-align:left}.pcw-history-item-content:hover{background:var(--pcw-agent-bubble, #f3f4f6)}.pcw-history-item-title{font-size:13px;font-weight:500;color:var(--pcw-text, #1a1a1a);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.pcw-history-item-meta{display:flex;gap:8px;margin-top:4px;font-size:11px;color:var(--pcw-text-muted, #6b7280)}.pcw-history-item-tags{padding:0 12px 8px;display:flex;align-items:center;gap:4px;flex-wrap:wrap}.pcw-history-item-tag-list{display:flex;align-items:center;gap:4px;flex-wrap:wrap}.pcw-tag-badge{display:inline-flex;align-items:center;gap:2px;font-size:11px;padding:1px 6px;border-radius:10px;background:var(--pcw-primary, #2563eb);color:#fff;white-space:nowrap}.pcw-tag-badge--small{font-size:10px;padding:0 5px}.pcw-tag-remove{background:none;border:none;color:inherit;cursor:pointer;padding:0 2px;font-size:10px;line-height:1;opacity:.8}.pcw-tag-remove:hover{opacity:1}.pcw-tag-editor{display:flex;align-items:center;gap:4px;flex-wrap:wrap}.pcw-tag-input{font-size:11px;padding:2px 6px;border:1px solid var(--pcw-border, #e5e7eb);border-radius:10px;outline:none;width:80px;background:var(--pcw-bg, #ffffff);color:var(--pcw-text, #1a1a1a)}.pcw-tag-input:focus{border-color:var(--pcw-primary, #2563eb)}.pcw-tag-add-btn{font-size:11px;width:20px;height:20px;border-radius:50%;border:1px dashed var(--pcw-border, #e5e7eb);background:none;color:var(--pcw-text-muted, #6b7280);cursor:pointer;display:flex;align-items:center;justify-content:center;padding:0}.pcw-tag-add-btn:hover{border-color:var(--pcw-primary, #2563eb);color:var(--pcw-primary, #2563eb)}.pcw-tag-edit-btn{background:none;border:none;cursor:pointer;padding:2px;color:var(--pcw-text-muted, #6b7280);display:flex;align-items:center}.pcw-tag-edit-btn:hover{color:var(--pcw-primary, #2563eb)}.pcw-info-card__header{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:4px}.pcw-info-card__title{font-weight:600;font-size:13px}.pcw-info-card__status{padding:1px 6px;border-radius:4px;font-size:10px;font-weight:600;text-transform:uppercase}.pcw-info-card__status--ok{background:#dcfce7;color:#166534}.pcw-info-card__status--warning{background:#fef3c7;color:#92400e}.pcw-info-card__status--critical{background:#fee2e2;color:#991b1b}.pcw-info-card__status--info{background:#dbeafe;color:#1e40af}.pcw-info-card__subtitle{font-size:12px;color:var(--pcw-text-muted);margin-bottom:4px}.pcw-info-card__description{font-size:12px;line-height:1.4;margin:0 0 6px;color:var(--pcw-text)}.pcw-info-card__fields{display:flex;flex-direction:column;gap:2px;margin-bottom:6px;padding:4px 6px;background:var(--pcw-agent-bubble);border-radius:4px}.pcw-info-card__field{display:flex;justify-content:space-between;padding:1px 0;font-size:11px}.pcw-info-card__field-label{color:var(--pcw-text-muted)}.pcw-info-card__field-value{font-weight:500}.pcw-info-card__tags{display:flex;flex-wrap:wrap;gap:4px;margin-bottom:6px}.pcw-info-card__tag{display:inline-block;padding:1px 6px;border-radius:4px;background:#dbeafe;color:#1e40af;font-size:10px;font-weight:500}.pcw-info-card__actions{display:flex;gap:6px;margin-top:6px}.pcw-info-card__btn{padding:4px 10px;border:1px solid var(--pcw-primary);border-radius:4px;background:var(--pcw-primary);color:#fff;font-size:11px;font-weight:500;cursor:pointer;font-family:inherit}.pcw-info-card__btn:hover{opacity:.9}.pcw-metric{text-align:center;padding:12px 10px}.pcw-metric__label{font-size:11px;font-weight:500;color:var(--pcw-text-muted);margin-bottom:4px;text-transform:uppercase;letter-spacing:.03em}.pcw-metric__value-row{display:flex;align-items:baseline;justify-content:center;gap:4px}.pcw-metric__value{font-size:28px;font-weight:700;line-height:1.2;color:var(--pcw-text)}.pcw-metric__unit{font-size:13px;color:var(--pcw-text-muted)}.pcw-metric__trend{font-size:18px;font-weight:600}.pcw-metric__trend--up{color:#16a34a}.pcw-metric__trend--down{color:#dc2626}.pcw-metric__trend--flat{color:#ca8a04}.pcw-metric__description{font-size:11px;color:var(--pcw-text-muted);margin-top:4px}.pcw-metric__previous{font-size:10px;color:var(--pcw-text-muted);margin-top:2px}.pcw-header__badge{font-size:10px;padding:1px 6px;margin-left:6px;border-radius:10px;background:var(--pcw-text-muted, #6b7280);color:#fff;vertical-align:middle;font-weight:400}
|
|
5
|
+
*/.pcw-widget{--pcw-primary: #1e40af;--pcw-bg: #ffffff;--pcw-font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;--pcw-font-size: 14px;--pcw-radius: 8px;--pcw-user-bubble: #1e40af;--pcw-agent-bubble: #f3f4f6;--pcw-tool-call-bg: #f9fafb;--pcw-text: #111827;--pcw-text-muted: #6b7280;--pcw-border: #e5e7eb;--pcw-shadow: 0 4px 6px -1px rgba(0, 0, 0, .1), 0 2px 4px -1px rgba(0, 0, 0, .06);font-family:var(--pcw-font);font-size:var(--pcw-font-size);color:var(--pcw-text);box-sizing:border-box;line-height:1.5}.pcw-widget *,.pcw-widget *:before,.pcw-widget *:after{box-sizing:border-box}.pcw-widget--inline{display:flex;flex-direction:column;height:100%;width:100%;background:var(--pcw-bg);border-radius:var(--pcw-radius);overflow:hidden}.pcw-widget--right{position:fixed;top:0;right:0;width:400px;height:100vh;background:var(--pcw-bg);box-shadow:var(--pcw-shadow);z-index:9999;display:flex;flex-direction:column}.pcw-widget--floating{position:fixed;bottom:24px;right:24px;width:400px;height:600px;max-height:calc(100vh - 48px);background:var(--pcw-bg);border-radius:var(--pcw-radius);box-shadow:var(--pcw-shadow);z-index:9999;display:flex;flex-direction:column;overflow:hidden}.pcw-widget--bottom{position:fixed;bottom:0;left:0;right:0;height:400px;background:var(--pcw-bg);box-shadow:0 -2px 10px #0000001a;z-index:9999;display:flex;flex-direction:column}.pcw-header{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;border-bottom:1px solid var(--pcw-border);background:var(--pcw-bg);flex-shrink:0}.pcw-header__title{font-weight:600;font-size:15px;margin:0}.pcw-header__close{background:none;border:none;cursor:pointer;padding:4px;color:var(--pcw-text-muted);font-size:18px;line-height:1}.pcw-header__close:hover{color:var(--pcw-text)}.pcw-messages{flex:1;overflow-y:auto;padding:16px;display:flex;flex-direction:column;gap:12px}.pcw-messages--empty{flex:1;display:flex;align-items:center;justify-content:center;color:var(--pcw-text-muted);padding:16px}.pcw-bubble{max-width:80%;padding:8px 12px;border-radius:var(--pcw-radius);word-wrap:break-word;white-space:pre-wrap}.pcw-bubble--user{align-self:flex-end;background:var(--pcw-user-bubble);color:#fff}.pcw-bubble--assistant{align-self:flex-start;background:var(--pcw-agent-bubble);color:var(--pcw-text)}.pcw-bubble__text{margin:0;font-size:var(--pcw-font-size);line-height:1.5}.pcw-bubble__extras{display:flex;flex-direction:column;gap:8px;margin-top:8px}.pcw-tool-call{background:var(--pcw-tool-call-bg);border:1px solid var(--pcw-border);border-radius:6px;padding:8px;font-size:12px}.pcw-tool-call__header{display:flex;align-items:center;gap:6px;cursor:pointer;background:none;border:none;width:100%;text-align:left;padding:0;font-family:inherit;font-size:inherit;color:var(--pcw-text)}.pcw-tool-call__chevron{flex-shrink:0;font-size:10px;color:var(--pcw-text-muted)}.pcw-tool-call__name{font-family:monospace;font-weight:500}.pcw-tool-call__status{margin-left:auto;padding:1px 6px;border-radius:4px;font-size:10px;font-weight:500;text-transform:uppercase}.pcw-tool-call__status--running{background:#dbeafe;color:#1e40af}.pcw-tool-call__status--success{background:#dcfce7;color:#166534}.pcw-tool-call__status--error{background:#fee2e2;color:#991b1b}.pcw-tool-call__details{margin-top:8px;background:var(--pcw-agent-bubble);border-radius:4px;padding:8px;overflow-x:auto;font-family:monospace;font-size:11px;white-space:pre-wrap}.pcw-tool-call__subagent{padding:2px 0 2px 12px;border-left:2px solid var(--pcw-border, #e5e7eb);margin:4px 0 4px 8px}.pcw-subagent-row{font-size:12px;color:var(--pcw-text-muted, #6b7280)}.pcw-subagent-row__header{display:flex;align-items:center;gap:5px;width:100%;padding:3px 4px;border:none;border-radius:3px;background:none;cursor:pointer;font:inherit;color:inherit;text-align:left}.pcw-subagent-row__header:hover{background:var(--pcw-bg-hover, rgba(0, 0, 0, .04))}.pcw-subagent-row__header--static{cursor:default}.pcw-subagent-row__header--static:hover{background:none}.pcw-subagent-row__chevron{font-size:8px;width:10px;flex-shrink:0;opacity:.5}.pcw-subagent-row__icon{width:14px;flex-shrink:0;text-align:center;color:#16a34a}.pcw-subagent-row__icon--error{color:#dc2626}.pcw-subagent-row__name{font-family:var(--pcw-font-mono, ui-monospace, monospace);font-weight:500}.pcw-subagent-row__detail{margin:2px 0 4px 29px}.pcw-subagent-row__result,.pcw-subagent-row__error,.pcw-subagent-row__args{margin:0;padding:6px 8px;border-radius:4px;background:var(--pcw-bg-code, #f3f4f6);font-family:var(--pcw-font-mono, ui-monospace, monospace);font-size:11px;line-height:1.5;white-space:pre-wrap;word-break:break-word;max-height:200px;overflow-y:auto}.pcw-subagent-row__error{color:#dc2626;background:#fef2f2}.pcw-subagent-row__args{margin-top:4px;opacity:.8}.pcw-dispatch-args{margin:6px 0 2px;display:flex;flex-direction:column;gap:3px}.pcw-dispatch-args__row{display:flex;gap:6px;align-items:baseline;line-height:1.4}.pcw-dispatch-args__label{flex-shrink:0;width:56px;font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.03em;color:var(--pcw-text-muted, #6b7280)}.pcw-dispatch-args__value{font-size:12px;color:var(--pcw-text, #111827);line-height:1.4}.pcw-dispatch-args__value--mono{font-family:var(--pcw-font-mono, ui-monospace, monospace);font-weight:500}.pcw-dispatch-args__tags{display:flex;flex-wrap:wrap;gap:3px}.pcw-dispatch-args__tag{padding:0 5px;border-radius:3px;font-size:11px;font-family:var(--pcw-font-mono, ui-monospace, monospace);background:var(--pcw-bg-code, #f3f4f6);color:var(--pcw-text-muted, #6b7280)}.pcw-dispatch-details{margin-top:6px;border-top:1px solid var(--pcw-border, #e5e7eb);padding-top:4px}.pcw-dispatch-details__toggle{display:flex;align-items:center;gap:5px;background:none;border:none;padding:3px 0;cursor:pointer;font:inherit;font-size:11px;font-weight:500;color:var(--pcw-text-muted, #6b7280)}.pcw-dispatch-details__toggle:hover{color:var(--pcw-text, #111827)}.pcw-dispatch-details__count{margin-left:4px;font-weight:400;opacity:.7}.pcw-dispatch-details__body{margin-top:4px}.pcw-tool-call__subagent-summary{padding:8px 10px;margin:4px 0;font-size:12px;line-height:1.5;color:var(--pcw-text, #111827);background:var(--pcw-agent-bubble, #f3f4f6);border-radius:6px;max-height:400px;overflow-y:auto}.pcw-formatted-text{white-space:normal}.pcw-formatted-text p{margin:0 0 4px}.pcw-formatted-text p:last-child{margin-bottom:0}.pcw-md-h1,.pcw-md-h2,.pcw-md-h3,.pcw-md-h4{margin:10px 0 4px;line-height:1.3}.pcw-md-h1{font-size:15px;font-weight:700}.pcw-md-h2{font-size:14px;font-weight:600}.pcw-md-h3{font-size:13px;font-weight:600}.pcw-md-h4{font-size:12px;font-weight:600}.pcw-md-h1:first-child,.pcw-md-h2:first-child,.pcw-md-h3:first-child,.pcw-md-h4:first-child{margin-top:0}.pcw-md-list{margin:2px 0 4px;padding-left:20px}.pcw-md-list li{margin:1px 0}.pcw-md-list:last-child{margin-bottom:0}.pcw-md-code{padding:1px 4px;border-radius:3px;font-family:var(--pcw-font-mono, ui-monospace, monospace);font-size:.9em;background:var(--pcw-bg-code, rgba(0, 0, 0, .06))}.pcw-md-codeblock{margin:4px 0;padding:8px;border-radius:4px;background:var(--pcw-bg-code, #f3f4f6);font-family:var(--pcw-font-mono, ui-monospace, monospace);font-size:11px;line-height:1.5;overflow-x:auto;white-space:pre}.pcw-md-codeblock code{background:none;padding:0}.pcw-formatted-text strong{font-weight:600}.pcw-formatted-text a{color:var(--pcw-primary, #1e40af);text-decoration:underline}.pcw-dispatch-streaming{border-top:1px solid var(--pcw-border, #e5e7eb);padding:8px 12px;max-height:200px;overflow-y:auto}.pcw-subagent-inline-tool{display:flex;align-items:center;gap:5px;padding:3px 4px;font-size:12px;color:var(--pcw-text-muted, #6b7280)}.pcw-subagent-row__icon--running{color:#2563eb}.pcw-dispatch-inline-text{padding:2px 4px;font-size:12px;color:var(--pcw-text-muted, #6b7280)}.pcw-tool-call__header--static{cursor:default}.pcw-tool-call__error{margin-top:4px;color:#dc2626;font-size:11px}.pcw-tool-call__duration{color:var(--pcw-text-muted);font-size:10px;margin-left:4px}.pcw-kb-proposal{background:#fffbeb;border:1px solid #fbbf24;border-radius:6px;padding:8px 12px;font-size:12px}.pcw-kb-proposal__header{display:flex;align-items:center;gap:6px;margin-bottom:4px}.pcw-kb-proposal__icon{font-size:14px}.pcw-kb-proposal__title{font-weight:600;font-size:13px}.pcw-kb-proposal__scope{padding:1px 6px;border-radius:4px;font-size:10px;font-weight:500;text-transform:uppercase;background:#fef3c7;color:#92400e;margin-left:auto}.pcw-kb-proposal__reasoning{color:var(--pcw-text-muted);font-size:12px;margin:0}.pcw-skill-pill{display:inline-flex;align-items:center;gap:4px;padding:2px 8px;border-radius:12px;background:#ede9fe;color:#5b21b6;font-size:11px;font-weight:500;align-self:flex-start}.pcw-streaming{display:flex;align-items:center;gap:4px;padding:8px 16px;align-self:flex-start}.pcw-streaming__dot{width:6px;height:6px;border-radius:50%;background:var(--pcw-text-muted);animation:pcw-bounce 1.4s ease-in-out infinite}.pcw-streaming__dot:nth-child(1){animation-delay:-.32s}.pcw-streaming__dot:nth-child(2){animation-delay:-.16s}@keyframes pcw-bounce{0%,80%,to{transform:scale(0)}40%{transform:scale(1)}}.pcw-input{display:flex;align-items:flex-end;gap:8px;padding:12px 16px;border-top:1px solid var(--pcw-border);background:var(--pcw-bg);flex-shrink:0}.pcw-input__textarea{flex:1;min-height:40px;max-height:120px;padding:8px 12px;border:1px solid var(--pcw-border);border-radius:6px;font-family:var(--pcw-font);font-size:var(--pcw-font-size);resize:none;outline:none;line-height:1.5;color:var(--pcw-text);background:var(--pcw-bg)}.pcw-input__textarea:focus{border-color:var(--pcw-primary);box-shadow:0 0 0 2px #1e40af1a}.pcw-input__textarea::placeholder{color:var(--pcw-text-muted)}.pcw-input__textarea:disabled{opacity:.5;cursor:not-allowed}.pcw-input__send{display:flex;align-items:center;justify-content:center;width:36px;height:36px;border:none;border-radius:6px;background:var(--pcw-primary);color:#fff;cursor:pointer;flex-shrink:0;transition:opacity .15s}.pcw-input__send:hover:not(:disabled){opacity:.9}.pcw-input__send:disabled{opacity:.4;cursor:not-allowed}.pcw-input__send svg{width:16px;height:16px}.pcw-input__stop{background:var(--pcw-danger, #dc2626)}.pcw-input__stop:hover{opacity:.9}.pcw-toggle{position:fixed;bottom:24px;right:24px;width:56px;height:56px;border-radius:50%;background:var(--pcw-primary);color:#fff;border:none;cursor:pointer;box-shadow:var(--pcw-shadow);display:flex;align-items:center;justify-content:center;z-index:9998;transition:transform .15s}.pcw-toggle:hover{transform:scale(1.05)}.pcw-toggle svg{width:24px;height:24px}.pcw-error{padding:8px 16px;background:#fee2e2;color:#991b1b;font-size:12px;border-top:1px solid #fecaca}.pcw-widget-card{border:1px solid var(--pcw-border);border-radius:6px;padding:10px;margin:4px 0;font-size:12px;background:var(--pcw-bg)}.pcw-widget-card--generic{background:var(--pcw-tool-call-bg)}.pcw-widget-card__header{display:flex;align-items:center;gap:6px;margin-bottom:6px}.pcw-widget-card__type{font-family:monospace;font-size:11px;color:var(--pcw-text-muted)}.pcw-widget-card__json{margin:0;font-size:11px;font-family:monospace;white-space:pre-wrap;overflow-x:auto;max-height:200px;overflow-y:auto;background:var(--pcw-agent-bubble);padding:6px;border-radius:4px}.pcw-entity-card__header{display:flex;align-items:baseline;gap:8px;margin-bottom:4px}.pcw-entity-card__mac{font-family:monospace;font-weight:600;font-size:13px}.pcw-entity-card__mfr{color:var(--pcw-text-muted);font-size:12px}.pcw-entity-card__protocols{display:flex;flex-wrap:wrap;gap:4px;margin-bottom:6px}.pcw-entity-card__protocol-badge{display:inline-block;padding:1px 6px;border-radius:4px;background:#dbeafe;color:#1e40af;font-size:10px;font-weight:500}.pcw-entity-card__zone{font-size:11px;color:var(--pcw-text-muted);margin-bottom:6px}.pcw-entity-card__factors{font-size:11px;margin:6px 0;padding:4px 6px;background:var(--pcw-agent-bubble);border-radius:4px}.pcw-entity-card__factor{display:flex;justify-content:space-between;padding:1px 0}.pcw-entity-card__meta{display:flex;gap:12px;font-size:11px;color:var(--pcw-text-muted);margin:4px 0}.pcw-entity-card__actions{display:flex;gap:6px;margin-top:6px}.pcw-entity-card__btn{padding:4px 10px;border:1px solid var(--pcw-primary);border-radius:4px;background:var(--pcw-primary);color:#fff;font-size:11px;font-weight:500;cursor:pointer;font-family:inherit}.pcw-entity-card__btn:hover{opacity:.9}.pcw-entity-card__btn--secondary{background:transparent;color:var(--pcw-primary)}.pcw-entity-card__btn--secondary:hover{background:#1e40af0d}.pcw-score-bar{margin:4px 0}.pcw-score-bar__label{font-size:11px;font-weight:500;margin-bottom:2px}.pcw-score-bar__track{height:6px;background:#e5e7eb;border-radius:3px;overflow:hidden}.pcw-score-bar__fill{height:100%;border-radius:3px;background:linear-gradient(to right,#10b981,#f59e0b,#ef4444);transition:width .3s ease}.pcw-alert-card__header{display:flex;align-items:center;gap:8px;margin-bottom:6px}.pcw-alert-card__severity{padding:2px 8px;border-radius:4px;font-size:10px;font-weight:600;text-transform:uppercase}.pcw-alert-card__severity--low{background:#f3f4f6;color:#374151}.pcw-alert-card__severity--medium{background:#fef3c7;color:#92400e}.pcw-alert-card__severity--high{background:#fed7aa;color:#9a3412}.pcw-alert-card__severity--critical{background:#fee2e2;color:#991b1b}.pcw-alert-card__type{font-weight:500}.pcw-alert-card__zone{color:var(--pcw-text-muted);font-size:11px;margin-left:auto}.pcw-alert-card__description{margin:0 0 6px;font-size:12px;line-height:1.4}.pcw-alert-card__devices{display:flex;flex-wrap:wrap;gap:4px;margin-bottom:4px}.pcw-alert-card__device-link{font-family:monospace;font-size:11px;color:var(--pcw-primary);background:none;border:none;cursor:pointer;padding:1px 4px;text-decoration:underline}.pcw-alert-card__device-link:hover{opacity:.7}.pcw-alert-card__protocols{display:flex;gap:4px;margin-bottom:4px}.pcw-alert-card__time{font-size:10px;color:var(--pcw-text-muted)}.pcw-timeline__label{font-weight:500;font-size:12px;margin-bottom:8px}.pcw-timeline__events{position:relative;padding-left:16px}.pcw-timeline__events:before{content:"";position:absolute;left:5px;top:0;bottom:0;width:2px;background:var(--pcw-border)}.pcw-timeline__event{position:relative;display:flex;align-items:flex-start;gap:8px;padding:4px 0}.pcw-timeline__marker{width:10px;height:10px;border-radius:50%;flex-shrink:0;margin-top:2px;position:relative;z-index:1;margin-left:-11px}.pcw-timeline__content{display:flex;align-items:baseline;gap:6px;flex-wrap:wrap}.pcw-timeline__time{font-size:10px;color:var(--pcw-text-muted);font-family:monospace}.pcw-timeline__event-label{font-size:12px}.pcw-comparison__title{font-weight:500;font-size:12px;margin-bottom:8px}.pcw-comparison__grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:8px}.pcw-comparison__item{border:1px solid var(--pcw-border);border-radius:4px;padding:8px;display:flex;flex-direction:column;gap:2px}.pcw-comparison__mac{font-family:monospace;font-weight:600;font-size:11px}.pcw-comparison__detail{font-size:11px;color:var(--pcw-text-muted)}.pcw-comparison__score{font-size:11px;font-weight:500}.pcw-data-table__title{font-weight:500;font-size:12px;margin-bottom:6px}.pcw-data-table__scroll{overflow-x:auto}.pcw-data-table__table{width:100%;border-collapse:collapse;font-size:11px}.pcw-data-table__table th,.pcw-data-table__table td{padding:4px 8px;text-align:left;border-bottom:1px solid var(--pcw-border)}.pcw-data-table__table th{font-weight:600;background:var(--pcw-agent-bubble);white-space:nowrap}.pcw-data-table__sortable{cursor:pointer;-webkit-user-select:none;user-select:none}.pcw-data-table__sortable:hover{background:#e5e7eb}.pcw-entity-list__title{font-weight:500;font-size:12px;margin-bottom:6px}.pcw-entity-list__sort{display:flex;align-items:center;gap:4px;font-size:10px;color:var(--pcw-text-muted);margin-bottom:6px}.pcw-entity-list__sort-btn{padding:1px 6px;border:1px solid var(--pcw-border);border-radius:3px;background:transparent;font-size:10px;cursor:pointer;font-family:inherit;color:var(--pcw-text-muted)}.pcw-entity-list__sort-btn--active{background:var(--pcw-primary);color:#fff;border-color:var(--pcw-primary)}.pcw-entity-list__row{cursor:pointer}.pcw-entity-list__row:hover{background:var(--pcw-agent-bubble)}.pcw-entity-list__row--expanded{background:#eff6ff}.pcw-entity-list__mac{font-family:monospace;font-size:11px}.pcw-entity-list__detail{padding:6px 8px;display:flex;gap:6px}.pcw-entity-list__more{text-align:center;font-size:11px;color:var(--pcw-text-muted);padding:4px}.pcw-scope-map__label{font-weight:500;font-size:12px;margin-bottom:6px}.pcw-scope-map__svg{width:100%;max-width:280px}.pcw-scope-map__zone{fill:#f3f4f6;stroke:#d1d5db;stroke-width:1}.pcw-scope-map__zone--highlight{fill:#fee2e2;stroke:#ef4444;stroke-width:2}.pcw-scope-map__zone-label{font-size:9px;font-weight:600;fill:#374151}.pcw-scope-map__zone-name{font-size:7px;fill:#6b7280}.pcw-scope-map__devices{display:flex;flex-wrap:wrap;gap:4px;margin-top:6px}.pcw-scope-map__device-badge{font-family:monospace;font-size:10px;padding:1px 4px;background:#fee2e2;border-radius:3px;color:#991b1b}.pcw-score-breakdown__label{font-weight:500;font-size:12px;margin-bottom:6px}.pcw-score-breakdown__factors{margin-top:8px;display:flex;flex-direction:column;gap:6px}.pcw-score-breakdown__factor{font-size:11px}.pcw-score-breakdown__factor-header{display:flex;justify-content:space-between;margin-bottom:2px}.pcw-score-breakdown__factor-name{text-transform:capitalize}.pcw-score-breakdown__factor-value{font-weight:600;color:var(--pcw-primary)}.pcw-score-breakdown__factor-bar{height:4px;background:#e5e7eb;border-radius:2px;overflow:hidden}.pcw-score-breakdown__factor-fill{height:100%;background:var(--pcw-primary);border-radius:2px;transition:width .3s ease}.pcw-score-breakdown__factor-desc{font-size:10px;color:var(--pcw-text-muted);margin-top:2px}.pcw-status-board__title{font-weight:500;font-size:12px;margin-bottom:6px}.pcw-status-board__items{display:flex;flex-direction:column;gap:4px}.pcw-status-board__item{padding:6px 8px;border-radius:4px;border-left:3px solid transparent}.pcw-status-board__item:hover{background:var(--pcw-agent-bubble)}.pcw-status-board__item--critical{border-left-color:#dc2626}.pcw-status-board__item--high{border-left-color:#ea580c}.pcw-status-board__item--medium{border-left-color:#ca8a04}.pcw-status-board__item--low{border-left-color:#2563eb}.pcw-status-board__item-header{display:flex;align-items:baseline;gap:8px;font-size:12px}.pcw-status-board__severity{font-size:9px;font-weight:700;padding:1px 4px;border-radius:3px}.pcw-status-board__severity--critical{background:#fee2e2;color:#dc2626}.pcw-status-board__severity--high{background:#ffedd5;color:#ea580c}.pcw-status-board__severity--medium{background:#fef9c3;color:#ca8a04}.pcw-status-board__severity--low{background:#dbeafe;color:#2563eb}.pcw-status-board__item-label{font-weight:500;flex:1}.pcw-status-board__item-status{font-size:10px;color:var(--pcw-text-muted)}.pcw-status-board__item-desc{font-size:11px;color:var(--pcw-text-muted);margin-top:2px}.pcw-widget-card--credential-input{background:var(--pcw-bg)}.pcw-credential-input__title{font-weight:600;font-size:13px;margin-bottom:10px}.pcw-credential-input__field{display:flex;flex-direction:column;gap:2px;margin-bottom:8px}.pcw-credential-input__label{font-size:11px;font-weight:500;color:var(--pcw-text)}.pcw-credential-input__input{padding:6px 8px;border:1px solid var(--pcw-border);border-radius:4px;font-family:var(--pcw-font);font-size:12px;color:var(--pcw-text);background:var(--pcw-bg);outline:none}.pcw-credential-input__input:focus{border-color:var(--pcw-primary);box-shadow:0 0 0 2px #1e40af1a}.pcw-credential-input__input:disabled{opacity:.5;cursor:not-allowed}.pcw-credential-input__submit{display:block;width:100%;padding:6px 12px;margin-top:4px;border:none;border-radius:4px;background:var(--pcw-primary);color:#fff;font-family:inherit;font-size:12px;font-weight:500;cursor:pointer;transition:opacity .15s}.pcw-credential-input__submit:hover:not(:disabled){opacity:.9}.pcw-credential-input__submit:disabled{opacity:.5;cursor:not-allowed}.pcw-credential-input__status{font-size:12px;padding:6px 8px;border-radius:4px;margin-bottom:6px}.pcw-credential-input__status--success{background:#dcfce7;color:#166534}.pcw-credential-input__status--error{background:#fee2e2;color:#991b1b}.pcw-widget-card--document-preview{background:var(--pcw-bg)}.pcw-document-preview__header{display:flex;align-items:center;gap:6px;margin-bottom:8px;flex-wrap:wrap}.pcw-document-preview__title{font-weight:600;font-size:13px}.pcw-document-preview__badge{padding:1px 6px;border-radius:4px;font-size:10px;font-weight:500;text-transform:uppercase}.pcw-document-preview__badge--category{background:#dbeafe;color:#1e40af}.pcw-document-preview__badge--action{background:#fef3c7;color:#92400e}.pcw-document-preview__badge--approved{background:#dcfce7;color:#166534}.pcw-document-preview__body{margin:0 0 8px;padding:8px;background:var(--pcw-agent-bubble);border-radius:4px;font-size:11px;font-family:monospace;white-space:pre-wrap;overflow-x:auto;max-height:240px;overflow-y:auto;line-height:1.5}.pcw-document-preview__body code{font-family:inherit;font-size:inherit}.pcw-document-preview__actions{display:flex;gap:6px;margin-top:6px}.pcw-document-preview__btn{padding:4px 10px;border-radius:4px;font-size:11px;font-weight:500;cursor:pointer;font-family:inherit}.pcw-document-preview__btn--primary{border:1px solid var(--pcw-primary);background:var(--pcw-primary);color:#fff}.pcw-document-preview__btn--primary:hover{opacity:.9}.pcw-document-preview__btn--secondary{border:1px solid var(--pcw-primary);background:transparent;color:var(--pcw-primary)}.pcw-document-preview__btn--secondary:hover{background:#1e40af0d}.pcw-document-preview__editor-container{display:flex;flex-direction:column}.pcw-document-preview__editor{width:100%;padding:8px;border:1px solid var(--pcw-border);border-radius:4px;font-family:monospace;font-size:11px;color:var(--pcw-text);background:var(--pcw-bg);resize:vertical;outline:none;line-height:1.5}.pcw-document-preview__editor:focus{border-color:var(--pcw-primary);box-shadow:0 0 0 2px #1e40af1a}.pcw-ask-user{border:1px solid var(--pcw-primary);border-radius:6px;padding:10px;margin:4px 0;font-size:12px;background:var(--pcw-bg)}.pcw-ask-user--submitted{border-color:var(--pcw-border);background:var(--pcw-tool-call-bg)}.pcw-ask-user__field{display:flex;flex-direction:column;gap:4px;margin-bottom:10px}.pcw-ask-user__label{font-size:12px;font-weight:500;color:var(--pcw-text);line-height:1.4}.pcw-ask-user__header{display:inline-block;padding:1px 6px;border-radius:4px;background:#ede9fe;color:#5b21b6;font-size:10px;font-weight:600;text-transform:uppercase;margin-right:6px;vertical-align:middle}.pcw-ask-user__textarea{padding:6px 8px;border:1px solid var(--pcw-border);border-radius:4px;font-family:var(--pcw-font);font-size:12px;color:var(--pcw-text);background:var(--pcw-bg);outline:none;resize:vertical;line-height:1.5}.pcw-ask-user__textarea:focus{border-color:var(--pcw-primary);box-shadow:0 0 0 2px #1e40af1a}.pcw-ask-user__textarea:disabled{opacity:.5;cursor:not-allowed}.pcw-ask-user__yesno{display:flex;gap:6px}.pcw-ask-user__yesno-btn{padding:4px 16px;border:1px solid var(--pcw-border);border-radius:4px;background:transparent;font-family:inherit;font-size:12px;font-weight:500;cursor:pointer;color:var(--pcw-text);transition:background .1s,border-color .1s}.pcw-ask-user__yesno-btn:hover:not(:disabled){border-color:var(--pcw-primary)}.pcw-ask-user__yesno-btn--active{background:var(--pcw-primary);border-color:var(--pcw-primary);color:#fff}.pcw-ask-user__yesno-btn:disabled{opacity:.5;cursor:not-allowed}.pcw-ask-user__choices{display:flex;flex-direction:column;gap:4px}.pcw-ask-user__choice{display:flex;align-items:flex-start;gap:6px;padding:4px 6px;border-radius:4px;cursor:pointer}.pcw-ask-user__choice:hover{background:var(--pcw-agent-bubble)}.pcw-ask-user__choice input{margin-top:2px;flex-shrink:0}.pcw-ask-user__choice-label{font-weight:500;font-size:12px}.pcw-ask-user__choice-desc{font-size:11px;color:var(--pcw-text-muted);margin-left:4px}.pcw-ask-user__submit{display:block;width:100%;padding:6px 12px;border:none;border-radius:4px;background:var(--pcw-primary);color:#fff;font-family:inherit;font-size:12px;font-weight:500;cursor:pointer;transition:opacity .15s}.pcw-ask-user__submit:hover:not(:disabled){opacity:.9}.pcw-ask-user__submit:disabled{opacity:.5;cursor:not-allowed}.pcw-ask-user__summary{display:flex;flex-direction:column;gap:2px;margin-bottom:6px}.pcw-ask-user__summary:last-child{margin-bottom:0}.pcw-ask-user__summary-q{font-size:11px;color:var(--pcw-text-muted)}.pcw-ask-user__summary-a{font-size:12px;font-weight:500;color:var(--pcw-text)}.pcw-history-drawer{position:absolute;top:0;left:0;right:0;bottom:0;background:var(--pcw-bg, #ffffff);z-index:10;display:flex;flex-direction:column;overflow:hidden}.pcw-history-header{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;border-bottom:1px solid var(--pcw-border, #e5e7eb)}.pcw-history-title{font-size:14px;font-weight:600;margin:0;color:var(--pcw-text, #1a1a1a)}.pcw-history-close{background:none;border:none;cursor:pointer;padding:4px;color:var(--pcw-text-muted, #6b7280);border-radius:4px}.pcw-history-close:hover{background:var(--pcw-border, #e5e7eb)}.pcw-history-new-chat{margin:8px 16px;padding:8px 12px;background:var(--pcw-primary, #2563eb);color:#fff;border:none;border-radius:var(--pcw-radius, 8px);cursor:pointer;font-size:13px;font-weight:500;text-align:center}.pcw-history-new-chat:hover{opacity:.9}.pcw-history-filters{display:flex;flex-wrap:wrap;gap:4px;padding:4px 16px 8px}.pcw-filter-chip{font-size:11px;padding:2px 8px;border-radius:12px;border:1px solid var(--pcw-border, #e5e7eb);background:transparent;color:var(--pcw-text-muted, #6b7280);cursor:pointer}.pcw-filter-chip:hover{background:var(--pcw-border, #e5e7eb)}.pcw-filter-chip--active{background:var(--pcw-primary, #2563eb);color:#fff;border-color:var(--pcw-primary, #2563eb)}.pcw-history-list{flex:1;overflow-y:auto;padding:0 8px 8px}.pcw-history-loading,.pcw-history-empty{padding:24px 16px;text-align:center;color:var(--pcw-text-muted, #6b7280);font-size:13px}.pcw-history-item{border-radius:var(--pcw-radius, 8px);border:1px solid var(--pcw-border, #e5e7eb);margin-bottom:6px;overflow:hidden}.pcw-history-item-content{display:block;width:100%;padding:10px 12px;background:none;border:none;cursor:pointer;text-align:left}.pcw-history-item-content:hover{background:var(--pcw-agent-bubble, #f3f4f6)}.pcw-history-item-title{font-size:13px;font-weight:500;color:var(--pcw-text, #1a1a1a);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.pcw-history-item-meta{display:flex;gap:8px;margin-top:4px;font-size:11px;color:var(--pcw-text-muted, #6b7280)}.pcw-history-item-tags{padding:0 12px 8px;display:flex;align-items:center;gap:4px;flex-wrap:wrap}.pcw-history-item-tag-list{display:flex;align-items:center;gap:4px;flex-wrap:wrap}.pcw-tag-badge{display:inline-flex;align-items:center;gap:2px;font-size:11px;padding:1px 6px;border-radius:10px;background:var(--pcw-primary, #2563eb);color:#fff;white-space:nowrap}.pcw-tag-badge--small{font-size:10px;padding:0 5px}.pcw-tag-remove{background:none;border:none;color:inherit;cursor:pointer;padding:0 2px;font-size:10px;line-height:1;opacity:.8}.pcw-tag-remove:hover{opacity:1}.pcw-tag-editor{display:flex;align-items:center;gap:4px;flex-wrap:wrap}.pcw-tag-input{font-size:11px;padding:2px 6px;border:1px solid var(--pcw-border, #e5e7eb);border-radius:10px;outline:none;width:80px;background:var(--pcw-bg, #ffffff);color:var(--pcw-text, #1a1a1a)}.pcw-tag-input:focus{border-color:var(--pcw-primary, #2563eb)}.pcw-tag-add-btn{font-size:11px;width:20px;height:20px;border-radius:50%;border:1px dashed var(--pcw-border, #e5e7eb);background:none;color:var(--pcw-text-muted, #6b7280);cursor:pointer;display:flex;align-items:center;justify-content:center;padding:0}.pcw-tag-add-btn:hover{border-color:var(--pcw-primary, #2563eb);color:var(--pcw-primary, #2563eb)}.pcw-tag-edit-btn{background:none;border:none;cursor:pointer;padding:2px;color:var(--pcw-text-muted, #6b7280);display:flex;align-items:center}.pcw-tag-edit-btn:hover{color:var(--pcw-primary, #2563eb)}.pcw-info-card__header{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:4px}.pcw-info-card__title{font-weight:600;font-size:13px}.pcw-info-card__status{padding:1px 6px;border-radius:4px;font-size:10px;font-weight:600;text-transform:uppercase}.pcw-info-card__status--ok{background:#dcfce7;color:#166534}.pcw-info-card__status--warning{background:#fef3c7;color:#92400e}.pcw-info-card__status--critical{background:#fee2e2;color:#991b1b}.pcw-info-card__status--info{background:#dbeafe;color:#1e40af}.pcw-info-card__subtitle{font-size:12px;color:var(--pcw-text-muted);margin-bottom:4px}.pcw-info-card__description{font-size:12px;line-height:1.4;margin:0 0 6px;color:var(--pcw-text)}.pcw-info-card__fields{display:flex;flex-direction:column;gap:2px;margin-bottom:6px;padding:4px 6px;background:var(--pcw-agent-bubble);border-radius:4px}.pcw-info-card__field{display:flex;justify-content:space-between;padding:1px 0;font-size:11px}.pcw-info-card__field-label{color:var(--pcw-text-muted)}.pcw-info-card__field-value{font-weight:500}.pcw-info-card__tags{display:flex;flex-wrap:wrap;gap:4px;margin-bottom:6px}.pcw-info-card__tag{display:inline-block;padding:1px 6px;border-radius:4px;background:#dbeafe;color:#1e40af;font-size:10px;font-weight:500}.pcw-info-card__actions{display:flex;gap:6px;margin-top:6px}.pcw-info-card__btn{padding:4px 10px;border:1px solid var(--pcw-primary);border-radius:4px;background:var(--pcw-primary);color:#fff;font-size:11px;font-weight:500;cursor:pointer;font-family:inherit}.pcw-info-card__btn:hover{opacity:.9}.pcw-metric{text-align:center;padding:12px 10px}.pcw-metric__label{font-size:11px;font-weight:500;color:var(--pcw-text-muted);margin-bottom:4px;text-transform:uppercase;letter-spacing:.03em}.pcw-metric__value-row{display:flex;align-items:baseline;justify-content:center;gap:4px}.pcw-metric__value{font-size:28px;font-weight:700;line-height:1.2;color:var(--pcw-text)}.pcw-metric__unit{font-size:13px;color:var(--pcw-text-muted)}.pcw-metric__trend{font-size:18px;font-weight:600}.pcw-metric__trend--up{color:#16a34a}.pcw-metric__trend--down{color:#dc2626}.pcw-metric__trend--flat{color:#ca8a04}.pcw-metric__description{font-size:11px;color:var(--pcw-text-muted);margin-top:4px}.pcw-metric__previous{font-size:10px;color:var(--pcw-text-muted);margin-top:2px}.pcw-header__badge{font-size:10px;padding:1px 6px;margin-left:6px;border-radius:10px;background:var(--pcw-text-muted, #6b7280);color:#fff;vertical-align:middle;font-weight:400}.pcw-feedback{display:flex;align-items:center;gap:2px;margin-top:4px;margin-left:2px}.pcw-feedback--submitted{opacity:.7}.pcw-feedback__btn{font-size:12px;padding:2px 4px;border:none;background:transparent;cursor:pointer;opacity:.3;border-radius:4px;transition:opacity .15s,background .15s}.pcw-feedback__btn:hover{opacity:.8;background:var(--pcw-bg-hover, rgba(0,0,0,.05))}.pcw-feedback__icon{font-size:12px}.pcw-feedback__icon--up{color:#10b981}.pcw-feedback__icon--down{color:#ef4444}.pcw-feedback__comment{display:flex;gap:6px;margin-top:4px;width:100%}.pcw-feedback__input{flex:1;font-size:12px;padding:4px 8px;border:1px solid var(--pcw-border, #e5e7eb);border-radius:6px;background:var(--pcw-bg, #fff);color:var(--pcw-text, #1f2937);outline:none}.pcw-feedback__input:focus{border-color:var(--pcw-primary, #4f46e5)}.pcw-feedback__input::placeholder{color:var(--pcw-text-muted, #9ca3af)}.pcw-feedback__submit{font-size:11px;padding:4px 10px;border:none;border-radius:6px;background:#ef44441a;color:#ef4444;cursor:pointer;transition:background .15s}.pcw-feedback__submit:hover{background:#ef444433}
|