@m6d/cortex-angular 0.15.2 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -6
- package/fesm2022/m6d-cortex-angular.mjs +19 -19
- package/package.json +1 -1
- package/types/m6d-cortex-angular.d.ts +23 -19
package/README.md
CHANGED
|
@@ -25,7 +25,7 @@ export class MyComponent {
|
|
|
25
25
|
The widget attaches its own stylesheet; add `@m6d/cortex-angular/theme.css` to
|
|
26
26
|
your styles to override its tokens in one place (see Theming).
|
|
27
27
|
|
|
28
|
-
`baseUrl` is the agent's URL: the engine's public origin (`ENGINE_PUBLIC_URL`) plus `/agents/<agent
|
|
28
|
+
`baseUrl` is the agent's URL: the engine's public origin (`ENGINE_PUBLIC_URL`) plus `/agents/<agent name>`. Add the page's origin to `ENGINE_CORS_ORIGINS`, or proxy the engine under your own origin as the samples do. The WebSocket URL is `baseUrl` plus `/ws`; set `wsUrl` only to override it, and point it at that same agent-scoped path. The bearer is the end user's token, which Cortex verifies the way the agent's auth says: a JWKS, a shared secret, or the agent's server. For an anonymous agent, leave `getHeaders` out: the widget signs in as a visitor, and Cortex gives the browser an ID it keeps in local storage. When the agent checks visitors with reCAPTCHA Enterprise, the widget loads Google's script with the agent's site key and runs the check invisibly. The widget hides the badge Google draws for the agent's site key, and Google's terms then ask your page to show its reCAPTCHA attribution. A badge your page draws for its own key stays.
|
|
29
29
|
|
|
30
30
|
No root-level providers are needed. Each widget is self-contained, so one page can render several widgets with different configs.
|
|
31
31
|
|
|
@@ -36,12 +36,11 @@ No root-level providers are needed. Each widget is self-contained, so one page c
|
|
|
36
36
|
| Property | Type | Description |
|
|
37
37
|
| -------------------------- | ------------------------------------------------- | ------------------------------------------------------------------------------- |
|
|
38
38
|
| `locale` | `'en' \| 'ar'` | Active locale; the widget lays out in its direction (default: `'en'`) |
|
|
39
|
-
| `transport.baseUrl` | `string \| () => string` | The agent's URL, `<engine origin>/agents/<
|
|
39
|
+
| `transport.baseUrl` | `string \| () => string` | The agent's URL, `<engine origin>/agents/<name>` |
|
|
40
40
|
| `transport.getHeaders?` | `() => Headers \| Promise<Headers>` | Request headers provider; `Headers` is `Record<string, string>` |
|
|
41
41
|
| `wsUrl` | `string \| false` | WebSocket URL override; `false` disables the socket (optional) |
|
|
42
42
|
| `viewMode` | `'helper' \| 'full'` | Compact panel or full layout with a sidebar (default: `'helper'`) |
|
|
43
43
|
| `theme` | `'light' \| 'dark' \| 'system'` | Color scheme (default: `'light'`) |
|
|
44
|
-
| `agentName` | `string \| { en, ar }` | Header title while no thread is selected (optional) |
|
|
45
44
|
| `thread` | `string` | A thread id to open on mount (optional) |
|
|
46
45
|
| `mediaRenderers` | `Record<string, MediaRenderer>` | Replace or add the media fences the assistant can draw (optional) |
|
|
47
46
|
| `trustSameOriginEmbeds` | `boolean` | Allow embedded tool pages served from this page's own origin (default: `false`) |
|
|
@@ -76,7 +75,7 @@ import { CortexChatWidgetComponent, CortexSlotDirective } from '@m6d/cortex-angu
|
|
|
76
75
|
<button class="cortex-widget__header-btn" (click)="chat.openHistory()">☰</button>
|
|
77
76
|
}
|
|
78
77
|
<div class="cortex-widget__chat-title-wrap">
|
|
79
|
-
<p class="cortex-widget__chat-title">{{ chat.title
|
|
78
|
+
<p class="cortex-widget__chat-title">{{ chat.title }}</p>
|
|
80
79
|
</div>
|
|
81
80
|
<button class="cortex-widget__header-btn" (click)="chat.newChat()">+</button>
|
|
82
81
|
</div>
|
|
@@ -123,8 +122,7 @@ One header serves both screens; `screen` says which is showing.
|
|
|
123
122
|
| -------------- | --------------------- | -------------------------------------------------------------------- |
|
|
124
123
|
| `screen` | `'chat' \| 'threads'` | Which screen the header is on |
|
|
125
124
|
| `viewMode` | `'helper' \| 'full'` | The configured view mode |
|
|
126
|
-
| `title` | `string
|
|
127
|
-
| `agentName` | `string \| undefined` | `agentName` in the widget's locale |
|
|
125
|
+
| `title` | `string` | The open thread's title, else the agent's display name or "New Chat" |
|
|
128
126
|
| `threadCount` | `number \| undefined` | How many conversations the history lists; undefined while it loads |
|
|
129
127
|
| `isWorking` | `boolean` | The agent is answering |
|
|
130
128
|
| `debug` | `{ shown, on }` | Whether Cortex offers the debug view, and whether it is on |
|
|
@@ -50,6 +50,9 @@ function checkAttachmentPolicy(file) {
|
|
|
50
50
|
return "ok";
|
|
51
51
|
}
|
|
52
52
|
var VISITOR_RECAPTCHA_ACTION = "cortex_visitor";
|
|
53
|
+
function localized(value, locale) {
|
|
54
|
+
return value[locale] ?? value.en ?? Object.values(value)[0];
|
|
55
|
+
}
|
|
53
56
|
var STATEMENT_TOOLS = ["executeCode", "queryDataset", "describeDataset"];
|
|
54
57
|
var APPROVAL_TITLE_FIELD = "approvalTitle";
|
|
55
58
|
function modelLineOf(input, field) {
|
|
@@ -640,14 +643,6 @@ function composerDrop(options) {
|
|
|
640
643
|
}
|
|
641
644
|
};
|
|
642
645
|
}
|
|
643
|
-
// src/internal/client/src/format/localized.ts
|
|
644
|
-
function localized(value, locale) {
|
|
645
|
-
if (value === undefined || typeof value === "string" || Array.isArray(value)) {
|
|
646
|
-
return value;
|
|
647
|
-
}
|
|
648
|
-
const byLocale = value;
|
|
649
|
-
return byLocale[locale] ?? byLocale.en ?? Object.values(byLocale)[0];
|
|
650
|
-
}
|
|
651
646
|
// src/internal/client/src/i18n/ar.json
|
|
652
647
|
var ar_default = {
|
|
653
648
|
translate_history: "السجل",
|
|
@@ -2448,6 +2443,7 @@ function createCortexWidget(options) {
|
|
|
2448
2443
|
selected: undefined,
|
|
2449
2444
|
session: BLANK_SESSION,
|
|
2450
2445
|
capabilities: undefined,
|
|
2446
|
+
displayName: undefined,
|
|
2451
2447
|
unanswered: undefined,
|
|
2452
2448
|
attachments: queue.getState(),
|
|
2453
2449
|
creating: false,
|
|
@@ -2564,13 +2560,14 @@ ${draft}` : text);
|
|
|
2564
2560
|
onAnswered: (capabilities) => {
|
|
2565
2561
|
update({
|
|
2566
2562
|
capabilities,
|
|
2563
|
+
displayName: capabilities.displayName,
|
|
2567
2564
|
unanswered: undefined,
|
|
2568
2565
|
debugMode: state.debugMode && capabilities.debug
|
|
2569
2566
|
});
|
|
2570
2567
|
if (answers())
|
|
2571
2568
|
session?.resumeAnswers();
|
|
2572
2569
|
},
|
|
2573
|
-
onMissed: (unanswered) => update({ unanswered })
|
|
2570
|
+
onMissed: (unanswered) => update({ unanswered, displayName: state.displayName ?? {} })
|
|
2574
2571
|
});
|
|
2575
2572
|
}
|
|
2576
2573
|
function followTitle() {
|
|
@@ -2873,8 +2870,15 @@ ${draft}` : text);
|
|
|
2873
2870
|
};
|
|
2874
2871
|
}
|
|
2875
2872
|
function partsOf(state) {
|
|
2876
|
-
const { threads, selected, capabilities, debugMode } = state;
|
|
2877
|
-
return {
|
|
2873
|
+
const { threads, selected, capabilities, displayName, debugMode } = state;
|
|
2874
|
+
return {
|
|
2875
|
+
threads,
|
|
2876
|
+
selected,
|
|
2877
|
+
capabilities,
|
|
2878
|
+
displayName,
|
|
2879
|
+
debugMode,
|
|
2880
|
+
isWorking: state.session.isAgentWorking
|
|
2881
|
+
};
|
|
2878
2882
|
}
|
|
2879
2883
|
function widgetParts(widget, source, config, composer) {
|
|
2880
2884
|
const locale = resolveLocale(config.locale);
|
|
@@ -2882,12 +2886,12 @@ function widgetParts(widget, source, config, composer) {
|
|
|
2882
2886
|
newChat: widget.newChat,
|
|
2883
2887
|
deleteThread: (threadId) => void widget.deleteThread(threadId)
|
|
2884
2888
|
} : undefined;
|
|
2889
|
+
const newChatTitle = source.displayName === undefined ? "" : localized(source.displayName, locale) ?? translate(locale, "translate_new_chat");
|
|
2885
2890
|
function header(screen) {
|
|
2886
2891
|
return {
|
|
2887
2892
|
screen,
|
|
2888
2893
|
viewMode: config.viewMode ?? "helper",
|
|
2889
|
-
title: source.selected?.title ??
|
|
2890
|
-
agentName: localized(config.agentName, locale),
|
|
2894
|
+
title: source.selected?.title ?? newChatTitle,
|
|
2891
2895
|
threadCount: source.threads?.length,
|
|
2892
2896
|
isWorking: source.isWorking,
|
|
2893
2897
|
debug: { shown: Boolean(source.capabilities?.debug), on: source.debugMode },
|
|
@@ -5398,9 +5402,7 @@ var ChatHeaderComponent = class ChatHeaderComponent {
|
|
|
5398
5402
|
</button>
|
|
5399
5403
|
|
|
5400
5404
|
<div class="cortex-widget__chat-title-wrap">
|
|
5401
|
-
<p class="cortex-widget__chat-title">
|
|
5402
|
-
{{ header.title ?? header.agentName ?? ('translate_new_chat' | translate) }}
|
|
5403
|
-
</p>
|
|
5405
|
+
<p class="cortex-widget__chat-title">{{ header.title }}</p>
|
|
5404
5406
|
</div>
|
|
5405
5407
|
|
|
5406
5408
|
@if (header.debug.shown) {
|
|
@@ -5539,9 +5541,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
5539
5541
|
</button>
|
|
5540
5542
|
|
|
5541
5543
|
<div class="cortex-widget__chat-title-wrap">
|
|
5542
|
-
<p class="cortex-widget__chat-title">
|
|
5543
|
-
{{ header.title ?? header.agentName ?? ('translate_new_chat' | translate) }}
|
|
5544
|
-
</p>
|
|
5544
|
+
<p class="cortex-widget__chat-title">{{ header.title }}</p>
|
|
5545
5545
|
</div>
|
|
5546
5546
|
|
|
5547
5547
|
@if (header.debug.shown) {
|
package/package.json
CHANGED
|
@@ -80,6 +80,8 @@ export type TokenUsage = {
|
|
|
80
80
|
* The widget hides UI for anything absent; Cortex enforces each.
|
|
81
81
|
*/
|
|
82
82
|
export type AgentCapabilities = {
|
|
83
|
+
/** The agent's display name per locale, which titles a new chat; `{}` for an agent without one. */
|
|
84
|
+
displayName: Partial<LocalizedText>;
|
|
83
85
|
attachments: boolean;
|
|
84
86
|
/**
|
|
85
87
|
* False when this caller may not send to the chat: the agent's `message`
|
|
@@ -121,6 +123,8 @@ export type Suggestion = {
|
|
|
121
123
|
/** The manifest's suggestion and greeting schemas are built from these. */
|
|
122
124
|
export type Suggestions = Record<Locale, Suggestion[]>;
|
|
123
125
|
export type Greeting = Record<Locale, string>;
|
|
126
|
+
/** Author-written copy the widget shows verbatim, one string per locale. */
|
|
127
|
+
export type LocalizedText = Record<Locale, string>;
|
|
124
128
|
export type TriggerFiringSummary = {
|
|
125
129
|
name: string;
|
|
126
130
|
firingId: string;
|
|
@@ -203,8 +207,6 @@ export type MediaRenderContext = {
|
|
|
203
207
|
*/
|
|
204
208
|
export type MediaRenderer = (host: HTMLElement, source: string, context: MediaRenderContext) => Promise<() => void>;
|
|
205
209
|
export type MediaRenderers = Partial<Record<string, MediaRenderer>>;
|
|
206
|
-
/** One value for every locale, or a map keyed by locale ('en', 'ar'). */
|
|
207
|
-
export type Localized<T> = T | Partial<Record<Locale, T>>;
|
|
208
210
|
export type CortexViewMode = "helper" | "full";
|
|
209
211
|
export type CortexTheme = "light" | "dark" | "system";
|
|
210
212
|
export type CortexToolCallContext = {
|
|
@@ -252,12 +254,6 @@ export type CortexConfig = {
|
|
|
252
254
|
* fence tag; `map` swaps the built-in Leaflet map for another provider.
|
|
253
255
|
*/
|
|
254
256
|
mediaRenderers?: MediaRenderers;
|
|
255
|
-
/**
|
|
256
|
-
* Chat header title while no thread is selected; defaults to a localized
|
|
257
|
-
* "New Chat". Like the other copy props, either one value for every locale
|
|
258
|
-
* or a map keyed by locale (`{ en: 'Support', ar: 'الدعم' }`).
|
|
259
|
-
*/
|
|
260
|
-
agentName?: Localized<string>;
|
|
261
257
|
/**
|
|
262
258
|
* A thread to open when the widget mounts, by id, once the thread list holds
|
|
263
259
|
* it: a deep link into one conversation, such as the console's inspector.
|
|
@@ -283,10 +279,11 @@ export type CortexConfig = {
|
|
|
283
279
|
export type CortexHeaderContext = {
|
|
284
280
|
screen: "chat" | "threads";
|
|
285
281
|
viewMode: CortexViewMode;
|
|
286
|
-
/**
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
282
|
+
/**
|
|
283
|
+
* The open thread's title, else the agent's display name in the widget's
|
|
284
|
+
* locale, else the built-in "New Chat"; empty while the handshake is out.
|
|
285
|
+
*/
|
|
286
|
+
title: string;
|
|
290
287
|
/** How many conversations the history lists; undefined while the first load is out. */
|
|
291
288
|
threadCount: number | undefined;
|
|
292
289
|
isWorking: boolean;
|
|
@@ -404,6 +401,12 @@ export type CortexWidgetState = {
|
|
|
404
401
|
session: ChatSessionState;
|
|
405
402
|
/** What Cortex offers this agent's clients; undefined until the handshake answers. */
|
|
406
403
|
capabilities: AgentCapabilities | undefined;
|
|
404
|
+
/**
|
|
405
|
+
* The agent's display name from the last handshake answered, kept while a
|
|
406
|
+
* new one is out; `{}` once the first try fails. Undefined only before the
|
|
407
|
+
* first answer or miss.
|
|
408
|
+
*/
|
|
409
|
+
displayName: AgentCapabilities["displayName"] | undefined;
|
|
407
410
|
/** Why the handshake has not answered yet, once a try has failed. */
|
|
408
411
|
unanswered: Unanswered | undefined;
|
|
409
412
|
/** The files held for the next message. */
|
|
@@ -420,7 +423,7 @@ export type CortexWidgetState = {
|
|
|
420
423
|
* one of its fields changes, which a streamed chunk does only as the turn
|
|
421
424
|
* starts and stops working, so a framework redraws them only then.
|
|
422
425
|
*/
|
|
423
|
-
parts: Pick<CortexWidgetState, "threads" | "selected" | "capabilities" | "debugMode"> & {
|
|
426
|
+
parts: Pick<CortexWidgetState, "threads" | "selected" | "capabilities" | "displayName" | "debugMode"> & {
|
|
424
427
|
isWorking: boolean;
|
|
425
428
|
};
|
|
426
429
|
};
|
|
@@ -490,6 +493,8 @@ type TokenUsage$1 = {
|
|
|
490
493
|
* The widget hides UI for anything absent; Cortex enforces each.
|
|
491
494
|
*/
|
|
492
495
|
export type AgentCapabilities$1 = {
|
|
496
|
+
/** The agent's display name per locale, which titles a new chat; `{}` for an agent without one. */
|
|
497
|
+
displayName: Partial<LocalizedText$1>;
|
|
493
498
|
attachments: boolean;
|
|
494
499
|
/**
|
|
495
500
|
* False when this caller may not send to the chat: the agent's `message`
|
|
@@ -515,6 +520,7 @@ type Suggestion$1 = {
|
|
|
515
520
|
};
|
|
516
521
|
type Suggestions$1 = Record<Locale$1, Suggestion$1[]>;
|
|
517
522
|
type Greeting$1 = Record<Locale$1, string>;
|
|
523
|
+
type LocalizedText$1 = Record<Locale$1, string>;
|
|
518
524
|
/**
|
|
519
525
|
* Response of `POST /chat/:threadId/tools/:toolCallId/initiate` for a pending
|
|
520
526
|
* call stamped with an embed. The payload is for the widget only; it never
|
|
@@ -599,7 +605,7 @@ declare class CortexChatService {
|
|
|
599
605
|
readonly debugMode: import("@angular/core").Signal<boolean>;
|
|
600
606
|
readonly turnFailure: import("@angular/core").Signal<TurnFailure | undefined>;
|
|
601
607
|
/** What the header, landing and history are drawn from: a streamed chunk leaves it as it was. */
|
|
602
|
-
readonly parts: import("@angular/core").Signal<Pick<CortexWidgetState, "threads" | "capabilities" | "debugMode" | "selected"> & {
|
|
608
|
+
readonly parts: import("@angular/core").Signal<Pick<CortexWidgetState, "threads" | "capabilities" | "debugMode" | "displayName" | "selected"> & {
|
|
603
609
|
isWorking: boolean;
|
|
604
610
|
}>;
|
|
605
611
|
constructor();
|
|
@@ -621,8 +627,7 @@ export declare class CortexChatWidgetComponent implements OnInit {
|
|
|
621
627
|
chatHeader: {
|
|
622
628
|
screen: "chat" | "threads";
|
|
623
629
|
viewMode: CortexViewMode;
|
|
624
|
-
title: string
|
|
625
|
-
agentName: string | undefined;
|
|
630
|
+
title: string;
|
|
626
631
|
threadCount: number | undefined;
|
|
627
632
|
isWorking: boolean;
|
|
628
633
|
debug: {
|
|
@@ -637,8 +642,7 @@ export declare class CortexChatWidgetComponent implements OnInit {
|
|
|
637
642
|
threadsHeader: {
|
|
638
643
|
screen: "chat" | "threads";
|
|
639
644
|
viewMode: CortexViewMode;
|
|
640
|
-
title: string
|
|
641
|
-
agentName: string | undefined;
|
|
645
|
+
title: string;
|
|
642
646
|
threadCount: number | undefined;
|
|
643
647
|
isWorking: boolean;
|
|
644
648
|
debug: {
|
|
@@ -695,7 +699,7 @@ export type SlotTemplateContext<Slot extends SlotName> = {
|
|
|
695
699
|
*
|
|
696
700
|
* <cortex-chat-widget [config]="config">
|
|
697
701
|
* <ng-template cortexSlot="header" let-chat>
|
|
698
|
-
* <div class="cortex-widget__chat-header">{{ chat.title
|
|
702
|
+
* <div class="cortex-widget__chat-header">{{ chat.title }}</div>
|
|
699
703
|
* </ng-template>
|
|
700
704
|
* </cortex-chat-widget>
|
|
701
705
|
*/
|