@m6d/cortex-angular 0.13.0 → 0.14.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 +22 -22
- package/fesm2022/m6d-cortex-angular.mjs +137 -92
- package/package.json +1 -1
- package/types/m6d-cortex-angular.d.ts +38 -15
package/README.md
CHANGED
|
@@ -42,7 +42,7 @@ No root-level providers are needed. Each widget is self-contained, so one page c
|
|
|
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
44
|
| `agentName` | `string \| { en, ar }` | Header title while no thread is selected (optional) |
|
|
45
|
-
| `
|
|
45
|
+
| `thread` | `string` | A thread id to open on mount (optional) |
|
|
46
46
|
| `mediaRenderers` | `Record<string, MediaRenderer>` | Replace or add the media fences the assistant can draw (optional) |
|
|
47
47
|
| `trustSameOriginEmbeds` | `boolean` | Allow embedded tool pages served from this page's own origin (default: `false`) |
|
|
48
48
|
| `hooks.onToolCall` | `(toolCall, context) => unknown` | Answers a client tool; return `undefined` for tools you do not own (optional) |
|
|
@@ -51,7 +51,7 @@ No root-level providers are needed. Each widget is self-contained, so one page c
|
|
|
51
51
|
| `toolComponents` | `Record<string, Type<CortexToolComponentInputs>>` | Custom Angular components for tool rendering (optional) |
|
|
52
52
|
| `injector` | `Injector` | Injector for `toolComponents` (optional) |
|
|
53
53
|
|
|
54
|
-
`transport.getHeaders` returns the headers every call carries, usually a bearer `Authorization`. Called straight from another origin, the engine accepts only `Authorization` and the headers the widget sets itself; route anything else through a same-origin proxy. The WebSocket takes its `token` query param from a bearer `Authorization` header when there is one.
|
|
54
|
+
`transport.getHeaders` returns the headers every call carries, usually a bearer `Authorization`. Called straight from another origin, the engine accepts only `Authorization` and the headers the widget sets itself; route anything else through a same-origin proxy. The WebSocket takes its `token` query param from a bearer `Authorization` header when there is one. The debug toggle shows only when Cortex offers this caller the debug view: always to a console operator, and to everyone only where the engine runs with `ENGINE_DEBUG=true`. Anyone else gets only what the widget's normal view draws, and so does a `toolComponents` entry for one of the agent's server tools: the model's line for the user as the call's input, and only whether it failed (or a dataset read's row count) as its output.
|
|
55
55
|
|
|
56
56
|
## Custom parts
|
|
57
57
|
|
|
@@ -119,19 +119,19 @@ for typing your own rows and chips.
|
|
|
119
119
|
|
|
120
120
|
One header serves both screens; `screen` says which is showing.
|
|
121
121
|
|
|
122
|
-
| Field | Type | Description
|
|
123
|
-
| -------------- | --------------------- |
|
|
124
|
-
| `screen` | `'chat' \| 'threads'` | Which screen the header is on
|
|
125
|
-
| `viewMode` | `'helper' \| 'full'` | The configured view mode
|
|
126
|
-
| `title` | `string \| null` | The open thread's title; `null` on a new chat
|
|
127
|
-
| `agentName` | `string \| undefined` | `agentName` in the widget's locale
|
|
128
|
-
| `threadCount` | `number \| undefined` | How many conversations the history lists; undefined while it loads
|
|
129
|
-
| `isWorking` | `boolean` | The agent is answering
|
|
130
|
-
| `debug` | `{ shown, on }` | Whether
|
|
131
|
-
| `newChat` | `() => void` | Starts a new chat
|
|
132
|
-
| `openHistory` | `() => void` | Shows the history: its screen, or the sidebar in full mode
|
|
133
|
-
| `closeHistory` | `() => void` | Returns to the open chat
|
|
134
|
-
| `toggleDebug` | `() => void` | Switches debug mode
|
|
122
|
+
| Field | Type | Description |
|
|
123
|
+
| -------------- | --------------------- | -------------------------------------------------------------------- |
|
|
124
|
+
| `screen` | `'chat' \| 'threads'` | Which screen the header is on |
|
|
125
|
+
| `viewMode` | `'helper' \| 'full'` | The configured view mode |
|
|
126
|
+
| `title` | `string \| null` | The open thread's title; `null` on a new chat |
|
|
127
|
+
| `agentName` | `string \| undefined` | `agentName` in the widget's locale |
|
|
128
|
+
| `threadCount` | `number \| undefined` | How many conversations the history lists; undefined while it loads |
|
|
129
|
+
| `isWorking` | `boolean` | The agent is answering |
|
|
130
|
+
| `debug` | `{ shown, on }` | Whether Cortex offers the debug view, and whether it is on |
|
|
131
|
+
| `newChat` | `() => void` | Starts a new chat; absent until Cortex confirms the caller may write |
|
|
132
|
+
| `openHistory` | `() => void` | Shows the history: its screen, or the sidebar in full mode |
|
|
133
|
+
| `closeHistory` | `() => void` | Returns to the open chat |
|
|
134
|
+
| `toggleDebug` | `() => void` | Switches debug mode |
|
|
135
135
|
|
|
136
136
|
### `landing`
|
|
137
137
|
|
|
@@ -152,13 +152,13 @@ landing for it.
|
|
|
152
152
|
|
|
153
153
|
The history's list. Its header is the `header` slot.
|
|
154
154
|
|
|
155
|
-
| Field | Type | Description
|
|
156
|
-
| ------------------ | --------------------------------- |
|
|
157
|
-
| `threads` | `ThreadSummary[] \| undefined` | Newest first; `undefined` while the first load is out
|
|
158
|
-
| `selectedThreadId` | `string \| undefined` | The open thread's id; `undefined` on a new chat
|
|
159
|
-
| `openThread` | `(thread: ThreadSummary) => void` | Opens a thread
|
|
160
|
-
| `deleteThread` | `(threadId: string) => void` | Deletes a thread
|
|
161
|
-
| `newChat` | `() => void` | Starts a new chat
|
|
155
|
+
| Field | Type | Description |
|
|
156
|
+
| ------------------ | --------------------------------- | -------------------------------------------------------------------- |
|
|
157
|
+
| `threads` | `ThreadSummary[] \| undefined` | Newest first; `undefined` while the first load is out |
|
|
158
|
+
| `selectedThreadId` | `string \| undefined` | The open thread's id; `undefined` on a new chat |
|
|
159
|
+
| `openThread` | `(thread: ThreadSummary) => void` | Opens a thread |
|
|
160
|
+
| `deleteThread` | `(threadId: string) => void` | Deletes a thread; absent until Cortex confirms the caller may write |
|
|
161
|
+
| `newChat` | `() => void` | Starts a new chat; absent until Cortex confirms the caller may write |
|
|
162
162
|
|
|
163
163
|
## Theming
|
|
164
164
|
|
|
@@ -49,6 +49,12 @@ function checkAttachmentPolicy(file) {
|
|
|
49
49
|
}
|
|
50
50
|
var STATEMENT_TOOLS = ["executeCode", "queryDataset", "describeDataset"];
|
|
51
51
|
var APPROVAL_TITLE_FIELD = "approvalTitle";
|
|
52
|
+
function approvalTitleOf(input) {
|
|
53
|
+
if (!input || typeof input !== "object" || !(APPROVAL_TITLE_FIELD in input))
|
|
54
|
+
return;
|
|
55
|
+
const title = input[APPROVAL_TITLE_FIELD];
|
|
56
|
+
return typeof title === "string" && title.trim() ? title.trim() : undefined;
|
|
57
|
+
}
|
|
52
58
|
function toolCallMetadataOf(part) {
|
|
53
59
|
const metadata = part.metadata;
|
|
54
60
|
return metadata?.cortex ?? undefined;
|
|
@@ -61,6 +67,8 @@ function approvalIdOf(part) {
|
|
|
61
67
|
return part.approval?.id ?? `approval_${part.id}`;
|
|
62
68
|
}
|
|
63
69
|
var TIMEZONE_HEADER = "X-Cortex-Timezone";
|
|
70
|
+
var OPERATOR_HEADER = "X-Cortex-Operator";
|
|
71
|
+
var INSPECT_HEADER = "X-Cortex-Inspect";
|
|
64
72
|
|
|
65
73
|
// src/internal/client/src/chat/api-client.ts
|
|
66
74
|
function resolveTransportHeaders(transport) {
|
|
@@ -323,6 +331,7 @@ var ar_default = {
|
|
|
323
331
|
translate_trigger_fired: "تم التشغيل بواسطة",
|
|
324
332
|
translate_trigger_payload: "الحمولة",
|
|
325
333
|
translate_messages_disabled: "يعمل هذا الوكيل من مشغّلاته فقط.",
|
|
334
|
+
translate_read_only: "أنت تطّلع على هذه المحادثة. لا يمكن إرسال شيء من هنا.",
|
|
326
335
|
translate_access_refused: "لم يقبل هذا الوكيل تسجيل دخولك.",
|
|
327
336
|
translate_agent_unreachable: "تعذّر الوصول إلى هذا الوكيل الآن. نعيد المحاولة...",
|
|
328
337
|
translate_agent_missing: "هذا الوكيل غير متاح.",
|
|
@@ -477,6 +486,7 @@ var en_default = {
|
|
|
477
486
|
translate_trigger_fired: "Triggered by",
|
|
478
487
|
translate_trigger_payload: "Payload",
|
|
479
488
|
translate_messages_disabled: "This agent only runs from its triggers.",
|
|
489
|
+
translate_read_only: "You're viewing this conversation. Nothing can be sent from here.",
|
|
480
490
|
translate_access_refused: "This agent did not accept your sign-in.",
|
|
481
491
|
translate_agent_unreachable: "This agent cannot be reached right now. Trying again...",
|
|
482
492
|
translate_agent_missing: "This agent is not available.",
|
|
@@ -725,19 +735,12 @@ function toolCallAnimation(part) {
|
|
|
725
735
|
rows: state === "complete" ? toolCallRows(part) : undefined
|
|
726
736
|
};
|
|
727
737
|
}
|
|
728
|
-
function approvalTitle(part) {
|
|
729
|
-
const input = part.input;
|
|
730
|
-
if (!input || typeof input !== "object" || !(APPROVAL_TITLE_FIELD in input))
|
|
731
|
-
return;
|
|
732
|
-
const title = input[APPROVAL_TITLE_FIELD];
|
|
733
|
-
return typeof title === "string" && title.trim() ? title.trim() : undefined;
|
|
734
|
-
}
|
|
735
738
|
function approvalCard(part, locale) {
|
|
736
739
|
const approved = part.approval?.approved;
|
|
737
740
|
const { state } = toolCallAnimation(part);
|
|
738
741
|
const decision = approved === undefined ? part.state === "approval-requested" ? "pending" : "cancelled" : !approved ? "declined" : state === "error" ? "failed" : "approved";
|
|
739
742
|
return {
|
|
740
|
-
sentence:
|
|
743
|
+
sentence: approvalTitleOf(part.input) ?? translate(locale, "translate_approval_action", { tool: wordsOf(part.name) }),
|
|
741
744
|
decision,
|
|
742
745
|
decisionKey: DECISION_KEYS[decision]
|
|
743
746
|
};
|
|
@@ -1529,7 +1532,7 @@ function createCortexSocket(options) {
|
|
|
1529
1532
|
resolveTransportHeaders(transport).then((headers) => {
|
|
1530
1533
|
if (closed)
|
|
1531
1534
|
return;
|
|
1532
|
-
ws = new WebSocket(
|
|
1535
|
+
ws = new WebSocket(appendAuthToUrl(wsUrl, headers));
|
|
1533
1536
|
ws.addEventListener("open", () => {
|
|
1534
1537
|
open = true;
|
|
1535
1538
|
const opened = ws;
|
|
@@ -1588,14 +1591,21 @@ function resolveWsUrl(wsUrl, baseUrl) {
|
|
|
1588
1591
|
parsed.pathname = parsed.pathname.replace(/\/$/, "") + "/ws";
|
|
1589
1592
|
return parsed.toString();
|
|
1590
1593
|
}
|
|
1591
|
-
function
|
|
1592
|
-
const
|
|
1593
|
-
|
|
1594
|
+
function appendAuthToUrl(wsUrl, headers) {
|
|
1595
|
+
const header = (name) => Object.entries(headers).find(([key]) => key.toLowerCase() === name.toLowerCase())?.[1];
|
|
1596
|
+
const bearer = header("Authorization");
|
|
1597
|
+
const params = Object.entries({
|
|
1598
|
+
token: bearer?.startsWith("Bearer ") ? bearer.slice(7) : undefined,
|
|
1599
|
+
operator: header(OPERATOR_HEADER),
|
|
1600
|
+
inspect: header(INSPECT_HEADER)
|
|
1601
|
+
}).filter((entry) => Boolean(entry[1]));
|
|
1602
|
+
if (params.length === 0)
|
|
1594
1603
|
return wsUrl;
|
|
1595
1604
|
const parsed = new URL(wsUrl, window.location.origin);
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1605
|
+
for (const [param, value] of params) {
|
|
1606
|
+
if (!parsed.searchParams.has(param))
|
|
1607
|
+
parsed.searchParams.set(param, value);
|
|
1608
|
+
}
|
|
1599
1609
|
return parsed.toString();
|
|
1600
1610
|
}
|
|
1601
1611
|
// src/internal/client/src/chat/ask-until-answered.ts
|
|
@@ -1816,7 +1826,7 @@ function splitTail(text, consumed, runs) {
|
|
|
1816
1826
|
if (end <= 0)
|
|
1817
1827
|
break;
|
|
1818
1828
|
let take = Math.min(end, run.length - consumed);
|
|
1819
|
-
if (take < end && /[\uDC00-\uDFFF]/.test(text
|
|
1829
|
+
if (take < end && /[\uDC00-\uDFFF]/.test(text.charAt(end - take)))
|
|
1820
1830
|
take += 1;
|
|
1821
1831
|
const span = document.createElement("span");
|
|
1822
1832
|
span.className = "cortex-stream-fade";
|
|
@@ -4562,17 +4572,19 @@ var ChatHeaderComponent = class ChatHeaderComponent2 {
|
|
|
4562
4572
|
template: `@let header = context();
|
|
4563
4573
|
|
|
4564
4574
|
<ng-template #newChatButton>
|
|
4565
|
-
|
|
4566
|
-
|
|
4567
|
-
|
|
4568
|
-
|
|
4569
|
-
|
|
4570
|
-
|
|
4571
|
-
|
|
4572
|
-
|
|
4573
|
-
<
|
|
4574
|
-
|
|
4575
|
-
|
|
4575
|
+
@if (header.newChat; as newChat) {
|
|
4576
|
+
<button
|
|
4577
|
+
type="button"
|
|
4578
|
+
(click)="newChat()"
|
|
4579
|
+
[attr.aria-label]="'translate_new_chat' | translate"
|
|
4580
|
+
[title]="'translate_new_chat' | translate"
|
|
4581
|
+
class="cortex-widget__header-btn cortex-widget__new-btn"
|
|
4582
|
+
>
|
|
4583
|
+
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true">
|
|
4584
|
+
<path d="M8 3v10M3 8h10" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" />
|
|
4585
|
+
</svg>
|
|
4586
|
+
</button>
|
|
4587
|
+
}
|
|
4576
4588
|
</ng-template>
|
|
4577
4589
|
|
|
4578
4590
|
@if (header.screen === 'threads') {
|
|
@@ -4701,17 +4713,19 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
4701
4713
|
template: `@let header = context();
|
|
4702
4714
|
|
|
4703
4715
|
<ng-template #newChatButton>
|
|
4704
|
-
|
|
4705
|
-
|
|
4706
|
-
|
|
4707
|
-
|
|
4708
|
-
|
|
4709
|
-
|
|
4710
|
-
|
|
4711
|
-
|
|
4712
|
-
<
|
|
4713
|
-
|
|
4714
|
-
|
|
4716
|
+
@if (header.newChat; as newChat) {
|
|
4717
|
+
<button
|
|
4718
|
+
type="button"
|
|
4719
|
+
(click)="newChat()"
|
|
4720
|
+
[attr.aria-label]="'translate_new_chat' | translate"
|
|
4721
|
+
[title]="'translate_new_chat' | translate"
|
|
4722
|
+
class="cortex-widget__header-btn cortex-widget__new-btn"
|
|
4723
|
+
>
|
|
4724
|
+
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true">
|
|
4725
|
+
<path d="M8 3v10M3 8h10" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" />
|
|
4726
|
+
</svg>
|
|
4727
|
+
</button>
|
|
4728
|
+
}
|
|
4715
4729
|
</ng-template>
|
|
4716
4730
|
|
|
4717
4731
|
@if (header.screen === 'threads') {
|
|
@@ -9694,9 +9708,10 @@ var MessageToolCallAnimatedComponent = class MessageToolCallAnimatedComponent2 {
|
|
|
9694
9708
|
} : null;
|
|
9695
9709
|
}, ...ngDevMode ? [{ debugName: "mountedComponent" }] : []);
|
|
9696
9710
|
clientToolFallback = signal(false, ...ngDevMode ? [{ debugName: "clientToolFallback" }] : []);
|
|
9697
|
-
|
|
9711
|
+
answers = computed(() => this.chatService.capabilities()?.messages === true, ...ngDevMode ? [{ debugName: "answers" }] : []);
|
|
9712
|
+
owed = computed(() => this.answers() && this.toolCallPart().state === "input-complete" && !this.chatService.isAgentWorking(), ...ngDevMode ? [{ debugName: "owed" }] : []);
|
|
9698
9713
|
showClientTool = computed(() => !this.clientToolFallback() && this.owed() && toolCallMetadataOf(this.toolCallPart())?.embed !== undefined, ...ngDevMode ? [{ debugName: "showClientTool" }] : []);
|
|
9699
|
-
approvalRequested = computed(() => this.toolCallPart().state === "approval-requested" && !this.chatService.isAgentWorking(), ...ngDevMode ? [{ debugName: "approvalRequested" }] : []);
|
|
9714
|
+
approvalRequested = computed(() => this.answers() && this.toolCallPart().state === "approval-requested" && !this.chatService.isAgentWorking(), ...ngDevMode ? [{ debugName: "approvalRequested" }] : []);
|
|
9700
9715
|
animation = computed(() => toolCallAnimation(this.toolCallPart()), ...ngDevMode ? [{ debugName: "animation" }] : []);
|
|
9701
9716
|
animState = computed(() => this.animation().state, ...ngDevMode ? [{ debugName: "animState" }] : []);
|
|
9702
9717
|
gated = computed(() => this.animation().gated, ...ngDevMode ? [{ debugName: "gated" }] : []);
|
|
@@ -11626,7 +11641,7 @@ var MessageListComponent = class MessageListComponent2 {
|
|
|
11626
11641
|
<cortex-message-aborted-flag [label]="failureLabel(failure)" />
|
|
11627
11642
|
<!-- The reason may name the model provider's answer: shown only where
|
|
11628
11643
|
the debug view is offered. -->
|
|
11629
|
-
@if (
|
|
11644
|
+
@if (chatService.capabilities()?.debug && failure.reason) {
|
|
11630
11645
|
<p class="cortex-aborted-flag__reason">{{ failure.reason }}</p>
|
|
11631
11646
|
}
|
|
11632
11647
|
}
|
|
@@ -11722,7 +11737,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
11722
11737
|
<cortex-message-aborted-flag [label]="failureLabel(failure)" />
|
|
11723
11738
|
<!-- The reason may name the model provider's answer: shown only where
|
|
11724
11739
|
the debug view is offered. -->
|
|
11725
|
-
@if (
|
|
11740
|
+
@if (chatService.capabilities()?.debug && failure.reason) {
|
|
11726
11741
|
<p class="cortex-aborted-flag__reason">{{ failure.reason }}</p>
|
|
11727
11742
|
}
|
|
11728
11743
|
}
|
|
@@ -11949,22 +11964,24 @@ var ThreadListComponent = class ThreadListComponent2 {
|
|
|
11949
11964
|
}
|
|
11950
11965
|
</button>
|
|
11951
11966
|
|
|
11952
|
-
|
|
11953
|
-
|
|
11954
|
-
|
|
11955
|
-
|
|
11956
|
-
|
|
11957
|
-
|
|
11958
|
-
|
|
11959
|
-
|
|
11960
|
-
<
|
|
11961
|
-
|
|
11962
|
-
|
|
11963
|
-
|
|
11964
|
-
|
|
11965
|
-
|
|
11966
|
-
|
|
11967
|
-
|
|
11967
|
+
@if (list.deleteThread; as deleteThread) {
|
|
11968
|
+
<button
|
|
11969
|
+
type="button"
|
|
11970
|
+
[attr.aria-label]="'translate_delete_conversation' | translate"
|
|
11971
|
+
(click)="deleteThread(thread.id)"
|
|
11972
|
+
class="cortex-widget__thread-delete"
|
|
11973
|
+
[class.cortex-widget__thread-delete--active]="isActive"
|
|
11974
|
+
>
|
|
11975
|
+
<svg width="12" height="12" viewBox="0 0 16 16" fill="none">
|
|
11976
|
+
<path
|
|
11977
|
+
d="M4 4l8 8M12 4l-8 8"
|
|
11978
|
+
stroke="currentColor"
|
|
11979
|
+
stroke-width="1.3"
|
|
11980
|
+
stroke-linecap="round"
|
|
11981
|
+
/>
|
|
11982
|
+
</svg>
|
|
11983
|
+
</button>
|
|
11984
|
+
}
|
|
11968
11985
|
|
|
11969
11986
|
<svg
|
|
11970
11987
|
class="cortex-widget__thread-arrow"
|
|
@@ -12010,12 +12027,14 @@ var ThreadListComponent = class ThreadListComponent2 {
|
|
|
12010
12027
|
<p class="cortex-widget__threads-empty-subtitle">
|
|
12011
12028
|
{{ 'translate_start_a_new_conversation' | translate }}
|
|
12012
12029
|
</p>
|
|
12013
|
-
|
|
12014
|
-
|
|
12015
|
-
|
|
12016
|
-
|
|
12017
|
-
|
|
12018
|
-
|
|
12030
|
+
@if (list.newChat; as newChat) {
|
|
12031
|
+
<button
|
|
12032
|
+
(click)="newChat()"
|
|
12033
|
+
class="cortex-widget__new-chat-btn cortex-widget__new-chat-btn--empty-state"
|
|
12034
|
+
>
|
|
12035
|
+
{{ 'translate_new_chat' | translate }}
|
|
12036
|
+
</button>
|
|
12037
|
+
}
|
|
12019
12038
|
</div>
|
|
12020
12039
|
}
|
|
12021
12040
|
`,
|
|
@@ -12105,22 +12124,24 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
12105
12124
|
}
|
|
12106
12125
|
</button>
|
|
12107
12126
|
|
|
12108
|
-
|
|
12109
|
-
|
|
12110
|
-
|
|
12111
|
-
|
|
12112
|
-
|
|
12113
|
-
|
|
12114
|
-
|
|
12115
|
-
|
|
12116
|
-
<
|
|
12117
|
-
|
|
12118
|
-
|
|
12119
|
-
|
|
12120
|
-
|
|
12121
|
-
|
|
12122
|
-
|
|
12123
|
-
|
|
12127
|
+
@if (list.deleteThread; as deleteThread) {
|
|
12128
|
+
<button
|
|
12129
|
+
type="button"
|
|
12130
|
+
[attr.aria-label]="'translate_delete_conversation' | translate"
|
|
12131
|
+
(click)="deleteThread(thread.id)"
|
|
12132
|
+
class="cortex-widget__thread-delete"
|
|
12133
|
+
[class.cortex-widget__thread-delete--active]="isActive"
|
|
12134
|
+
>
|
|
12135
|
+
<svg width="12" height="12" viewBox="0 0 16 16" fill="none">
|
|
12136
|
+
<path
|
|
12137
|
+
d="M4 4l8 8M12 4l-8 8"
|
|
12138
|
+
stroke="currentColor"
|
|
12139
|
+
stroke-width="1.3"
|
|
12140
|
+
stroke-linecap="round"
|
|
12141
|
+
/>
|
|
12142
|
+
</svg>
|
|
12143
|
+
</button>
|
|
12144
|
+
}
|
|
12124
12145
|
|
|
12125
12146
|
<svg
|
|
12126
12147
|
class="cortex-widget__thread-arrow"
|
|
@@ -12166,12 +12187,14 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
12166
12187
|
<p class="cortex-widget__threads-empty-subtitle">
|
|
12167
12188
|
{{ 'translate_start_a_new_conversation' | translate }}
|
|
12168
12189
|
</p>
|
|
12169
|
-
|
|
12170
|
-
|
|
12171
|
-
|
|
12172
|
-
|
|
12173
|
-
|
|
12174
|
-
|
|
12190
|
+
@if (list.newChat; as newChat) {
|
|
12191
|
+
<button
|
|
12192
|
+
(click)="newChat()"
|
|
12193
|
+
class="cortex-widget__new-chat-btn cortex-widget__new-chat-btn--empty-state"
|
|
12194
|
+
>
|
|
12195
|
+
{{ 'translate_new_chat' | translate }}
|
|
12196
|
+
</button>
|
|
12197
|
+
}
|
|
12175
12198
|
</div>
|
|
12176
12199
|
}
|
|
12177
12200
|
`
|
|
@@ -12243,6 +12266,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
12243
12266
|
var CortexChatWidgetComponent = class CortexChatWidgetComponent2 {
|
|
12244
12267
|
config = input.required(...ngDevMode ? [{ debugName: "config" }] : []);
|
|
12245
12268
|
debugMode = signal(false, ...ngDevMode ? [{ debugName: "debugMode" }] : []);
|
|
12269
|
+
writes = computed(() => this.chatService.capabilities()?.readOnly === false, ...ngDevMode ? [{ debugName: "writes" }] : []);
|
|
12246
12270
|
screen = signal("chat", ...ngDevMode ? [{ debugName: "screen" }] : []);
|
|
12247
12271
|
sidebarOpen = signal(false, ...ngDevMode ? [{ debugName: "sidebarOpen" }] : []);
|
|
12248
12272
|
viewMode = computed(() => this.config().viewMode ?? "helper", ...ngDevMode ? [{ debugName: "viewMode" }] : []);
|
|
@@ -12270,8 +12294,10 @@ var CortexChatWidgetComponent = class CortexChatWidgetComponent2 {
|
|
|
12270
12294
|
threads: this.threadService.threads(),
|
|
12271
12295
|
selectedThreadId: this.chatService.selectedThread()?.id,
|
|
12272
12296
|
openThread: (thread) => this.selectThread(thread),
|
|
12273
|
-
|
|
12274
|
-
|
|
12297
|
+
...this.writes() && {
|
|
12298
|
+
deleteThread: (threadId) => this.chatService.deleteThread(threadId).subscribe(),
|
|
12299
|
+
newChat: () => this.newChat()
|
|
12300
|
+
}
|
|
12275
12301
|
}), ...ngDevMode ? [{ debugName: "threadList" }] : []);
|
|
12276
12302
|
chatService;
|
|
12277
12303
|
queue;
|
|
@@ -12291,6 +12317,15 @@ var CortexChatWidgetComponent = class CortexChatWidgetComponent2 {
|
|
|
12291
12317
|
this.queue.store.clear(selectedThreadId);
|
|
12292
12318
|
selectedThreadId = nextThreadId;
|
|
12293
12319
|
}, { injector: this.injector });
|
|
12320
|
+
let openedConfigThread = false;
|
|
12321
|
+
effect(() => {
|
|
12322
|
+
const id = this.config().thread;
|
|
12323
|
+
const named = id && this.threadService.threads()?.find((thread) => thread.id === id);
|
|
12324
|
+
if (openedConfigThread || !named)
|
|
12325
|
+
return;
|
|
12326
|
+
openedConfigThread = true;
|
|
12327
|
+
untracked(() => this.selectThread(named));
|
|
12328
|
+
}, { injector: this.injector });
|
|
12294
12329
|
this.chatService.events$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((event) => {
|
|
12295
12330
|
if (event === "onError") {
|
|
12296
12331
|
this.queue.store.restoreConsumed(this.chatService.selectedThread()?.id);
|
|
@@ -12313,10 +12348,10 @@ var CortexChatWidgetComponent = class CortexChatWidgetComponent2 {
|
|
|
12313
12348
|
threadCount: this.threadService.threads()?.length,
|
|
12314
12349
|
isWorking: this.chatService.isAgentWorking(),
|
|
12315
12350
|
debug: {
|
|
12316
|
-
shown: Boolean(this.
|
|
12351
|
+
shown: Boolean(this.chatService.capabilities()?.debug),
|
|
12317
12352
|
on: this.debugMode()
|
|
12318
12353
|
},
|
|
12319
|
-
newChat: () => this.newChat(),
|
|
12354
|
+
...this.writes() && { newChat: () => this.newChat() },
|
|
12320
12355
|
openHistory: () => this.openHistory(),
|
|
12321
12356
|
closeHistory: () => this.closeHistory(),
|
|
12322
12357
|
toggleDebug: () => this.toggleDebugMode()
|
|
@@ -12507,7 +12542,12 @@ var CortexChatWidgetComponent = class CortexChatWidgetComponent2 {
|
|
|
12507
12542
|
</p>
|
|
12508
12543
|
} @else if (chatService.capabilities()?.messages === false) {
|
|
12509
12544
|
<p class="cortex-widget__messages-disabled">
|
|
12510
|
-
{{
|
|
12545
|
+
{{
|
|
12546
|
+
(chatService.capabilities()?.readOnly
|
|
12547
|
+
? 'translate_read_only'
|
|
12548
|
+
: 'translate_messages_disabled'
|
|
12549
|
+
) | translate
|
|
12550
|
+
}}
|
|
12511
12551
|
</p>
|
|
12512
12552
|
} @else if (chatService.capabilities() !== undefined) {
|
|
12513
12553
|
<cortex-chat-composer />
|
|
@@ -12708,7 +12748,12 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
12708
12748
|
</p>
|
|
12709
12749
|
} @else if (chatService.capabilities()?.messages === false) {
|
|
12710
12750
|
<p class="cortex-widget__messages-disabled">
|
|
12711
|
-
{{
|
|
12751
|
+
{{
|
|
12752
|
+
(chatService.capabilities()?.readOnly
|
|
12753
|
+
? 'translate_read_only'
|
|
12754
|
+
: 'translate_messages_disabled'
|
|
12755
|
+
) | translate
|
|
12756
|
+
}}
|
|
12712
12757
|
</p>
|
|
12713
12758
|
} @else if (chatService.capabilities() !== undefined) {
|
|
12714
12759
|
<cortex-chat-composer />
|
package/package.json
CHANGED
|
@@ -61,12 +61,23 @@ export type CreateThreadRequest = {
|
|
|
61
61
|
*/
|
|
62
62
|
export type AgentCapabilities = {
|
|
63
63
|
attachments: boolean;
|
|
64
|
-
/**
|
|
64
|
+
/**
|
|
65
|
+
* False when this caller may not send to the chat: the agent's `message`
|
|
66
|
+
* trigger is off, or the caller only reads (`readOnly`). The widget hides
|
|
67
|
+
* its composer and answers no tool call.
|
|
68
|
+
*/
|
|
65
69
|
messages: boolean;
|
|
70
|
+
/** True when the caller only reads, as an operator inspecting a user's thread does. */
|
|
71
|
+
readOnly: boolean;
|
|
66
72
|
/** Prompt chips on the blank-chat landing per locale; clicking one sends its `prompt` as the first message. */
|
|
67
73
|
suggestions: Suggestions;
|
|
68
74
|
/** Headline of the blank-chat landing per locale; "" falls back to the widget's built-in copy. */
|
|
69
75
|
greeting: Greeting;
|
|
76
|
+
/**
|
|
77
|
+
* Whether this caller gets the debug view: tool inputs and outputs, reasoning,
|
|
78
|
+
* model calls. Cortex sends anyone else only what the widget's normal UI draws.
|
|
79
|
+
*/
|
|
80
|
+
debug: boolean;
|
|
70
81
|
};
|
|
71
82
|
/**
|
|
72
83
|
* One landing-page chip: the widget shows `title` and sends `prompt` as the
|
|
@@ -165,7 +176,11 @@ export type CortexConfig = {
|
|
|
165
176
|
* or a map keyed by locale (`{ en: 'Support', ar: 'الدعم' }`).
|
|
166
177
|
*/
|
|
167
178
|
agentName?: Localized<string>;
|
|
168
|
-
|
|
179
|
+
/**
|
|
180
|
+
* A thread to open when the widget mounts, by id, once the thread list holds
|
|
181
|
+
* it: a deep link into one conversation, such as the console's inspector.
|
|
182
|
+
*/
|
|
183
|
+
thread?: string;
|
|
169
184
|
/**
|
|
170
185
|
* Render embedded tool pages served from this page's own origin with their
|
|
171
186
|
* full identity — which, same-origin, means no effective sandbox at all: such
|
|
@@ -193,12 +208,13 @@ export type CortexHeaderContext = {
|
|
|
193
208
|
/** How many conversations the history lists; undefined while the first load is out. */
|
|
194
209
|
threadCount: number | undefined;
|
|
195
210
|
isWorking: boolean;
|
|
196
|
-
/** Whether
|
|
211
|
+
/** Whether Cortex offers this caller the debug view, and whether it is on. */
|
|
197
212
|
debug: {
|
|
198
213
|
shown: boolean;
|
|
199
214
|
on: boolean;
|
|
200
215
|
};
|
|
201
|
-
|
|
216
|
+
/** Absent until the handshake says the caller may write; an operator inspecting a thread only reads. */
|
|
217
|
+
newChat?: () => void;
|
|
202
218
|
/** Shows the history: the history screen, or in full mode the sidebar where it is hidden. */
|
|
203
219
|
openHistory: () => void;
|
|
204
220
|
/** Returns to the open chat from wherever `openHistory` went. */
|
|
@@ -236,8 +252,9 @@ export type CortexThreadListContext = {
|
|
|
236
252
|
/** The open thread's id; undefined on a new chat. */
|
|
237
253
|
selectedThreadId: string | undefined;
|
|
238
254
|
openThread: (thread: ThreadSummary) => void;
|
|
239
|
-
|
|
240
|
-
|
|
255
|
+
/** Both absent until the handshake says the caller may write; an operator inspecting a thread only reads. */
|
|
256
|
+
deleteThread?: (threadId: string) => void;
|
|
257
|
+
newChat?: () => void;
|
|
241
258
|
};
|
|
242
259
|
/** Each part of the widget a consumer can draw itself, with the context it receives. */
|
|
243
260
|
export type CortexSlotContexts<View> = {
|
|
@@ -442,6 +459,12 @@ declare class CortexChatService {
|
|
|
442
459
|
export declare class CortexChatWidgetComponent implements OnInit {
|
|
443
460
|
readonly config: import("@angular/core").InputSignal<CortexAngularConfig>;
|
|
444
461
|
protected readonly debugMode: import("@angular/core").WritableSignal<boolean>;
|
|
462
|
+
/**
|
|
463
|
+
* Whether this caller may start and delete conversations: only once the
|
|
464
|
+
* handshake says so, like every capability-gated control, and never for a
|
|
465
|
+
* caller that only reads, as an operator inspecting a thread does.
|
|
466
|
+
*/
|
|
467
|
+
private readonly writes;
|
|
445
468
|
protected readonly screen: import("@angular/core").WritableSignal<"chat" | "threads">;
|
|
446
469
|
protected readonly sidebarOpen: import("@angular/core").WritableSignal<boolean>;
|
|
447
470
|
protected readonly viewMode: import("@angular/core").Signal<CortexViewMode>;
|
|
@@ -455,6 +478,10 @@ export declare class CortexChatWidgetComponent implements OnInit {
|
|
|
455
478
|
/** Why the handshake has not answered, worded for the composer's place. */
|
|
456
479
|
protected readonly unansweredNotice: import("@angular/core").Signal<"translate_access_refused" | "translate_agent_unreachable" | "translate_agent_missing" | undefined>;
|
|
457
480
|
protected readonly chatHeader: import("@angular/core").Signal<{
|
|
481
|
+
openHistory: () => void;
|
|
482
|
+
closeHistory: () => void;
|
|
483
|
+
toggleDebug: () => void;
|
|
484
|
+
newChat?: (() => void) | undefined;
|
|
458
485
|
screen: "chat" | "threads";
|
|
459
486
|
viewMode: CortexViewMode;
|
|
460
487
|
title: string | null;
|
|
@@ -465,12 +492,12 @@ export declare class CortexChatWidgetComponent implements OnInit {
|
|
|
465
492
|
shown: boolean;
|
|
466
493
|
on: boolean;
|
|
467
494
|
};
|
|
468
|
-
|
|
495
|
+
}>;
|
|
496
|
+
protected readonly threadsHeader: import("@angular/core").Signal<{
|
|
469
497
|
openHistory: () => void;
|
|
470
498
|
closeHistory: () => void;
|
|
471
499
|
toggleDebug: () => void;
|
|
472
|
-
|
|
473
|
-
protected readonly threadsHeader: import("@angular/core").Signal<{
|
|
500
|
+
newChat?: (() => void) | undefined;
|
|
474
501
|
screen: "chat" | "threads";
|
|
475
502
|
viewMode: CortexViewMode;
|
|
476
503
|
title: string | null;
|
|
@@ -481,10 +508,6 @@ export declare class CortexChatWidgetComponent implements OnInit {
|
|
|
481
508
|
shown: boolean;
|
|
482
509
|
on: boolean;
|
|
483
510
|
};
|
|
484
|
-
newChat: () => void;
|
|
485
|
-
openHistory: () => void;
|
|
486
|
-
closeHistory: () => void;
|
|
487
|
-
toggleDebug: () => void;
|
|
488
511
|
}>;
|
|
489
512
|
protected readonly landing: import("@angular/core").Signal<{
|
|
490
513
|
threads: ThreadSummary[] | undefined;
|
|
@@ -496,11 +519,11 @@ export declare class CortexChatWidgetComponent implements OnInit {
|
|
|
496
519
|
send: (prompt: string) => void;
|
|
497
520
|
}>;
|
|
498
521
|
protected readonly threadList: import("@angular/core").Signal<{
|
|
522
|
+
deleteThread?: ((threadId: string) => import("rxjs").Subscription) | undefined;
|
|
523
|
+
newChat?: (() => void) | undefined;
|
|
499
524
|
threads: ThreadSummary[] | undefined;
|
|
500
525
|
selectedThreadId: string | undefined;
|
|
501
526
|
openThread: (thread: ThreadSummary) => void;
|
|
502
|
-
deleteThread: (threadId: string) => import("rxjs").Subscription;
|
|
503
|
-
newChat: () => void;
|
|
504
527
|
}>;
|
|
505
528
|
protected chatService: CortexChatService;
|
|
506
529
|
protected queue: AttachmentQueueService;
|