@m6d/cortex-angular 0.3.0 → 0.4.1

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.
@@ -48,6 +48,9 @@ function toUiMessage(message) {
48
48
  return { ...message, role: message.role === "trigger" ? "user" : message.role };
49
49
  }
50
50
  var CLIENT_TOOL_ANSWERS_KEY = "clientToolAnswers";
51
+ function approvalIdOf(part) {
52
+ return part.approval?.id ?? `approval_${part.id}`;
53
+ }
51
54
  var TIMEZONE_HEADER = "X-Cortex-Timezone";
52
55
 
53
56
  // src/internal/client/src/chat/api-client.ts
@@ -93,7 +96,7 @@ function createCortexApiClient(getTransport) {
93
96
  }
94
97
  async function send(path, init) {
95
98
  const headers = new Headers(await resolveHeaders());
96
- new Headers(init?.headers).forEach(function(value, name) {
99
+ new Headers(init?.headers).forEach((value, name) => {
97
100
  headers.set(name, value);
98
101
  });
99
102
  if (init?.body instanceof FormData) {
@@ -138,10 +141,10 @@ function createCortexApiClient(getTransport) {
138
141
  method: "POST"
139
142
  });
140
143
  },
141
- async uploadAttachment(threadId, file) {
144
+ uploadAttachment(threadId, file) {
142
145
  const body = new FormData;
143
146
  body.append("file", file);
144
- return await send(`/threads/${threadId}/files`, {
147
+ return send(`/threads/${threadId}/files`, {
145
148
  method: "POST",
146
149
  body
147
150
  });
@@ -291,7 +294,7 @@ function approvalPrompt(part, locale) {
291
294
  const metadata = part.metadata;
292
295
  if (!metadata || typeof metadata !== "object" || !("cortex" in metadata))
293
296
  return;
294
- const cortex = metadata.cortex ?? undefined;
297
+ const cortex = metadata.cortex;
295
298
  return cortex?.approval?.[locale] || undefined;
296
299
  }
297
300
  function activityLabelKeys(activity) {
@@ -463,11 +466,7 @@ async function* withCommittedTranscript(stream, options, lastSent) {
463
466
  const boundary = local.findIndex((message) => message.id === lastSent);
464
467
  const queued = boundary === -1 ? [] : local.slice(boundary + 1).filter((message) => message.role === "user");
465
468
  options.onTranscriptCarried?.(chunk.timestamp ?? Date.now());
466
- const merged = {
467
- ...chunk,
468
- messages: [...chunk.messages, ...queued]
469
- };
470
- yield merged;
469
+ yield { ...chunk, messages: [...chunk.messages, ...queued] };
471
470
  }
472
471
  }
473
472
  function createCortexConnection(options) {
@@ -977,13 +976,13 @@ function createLocationPicker(host, options) {
977
976
  function showLocation(host, position, onFailed) {
978
977
  let disposed = false;
979
978
  let dispose;
980
- mountMap(host, { center: position, zoom: STREET_ZOOM, interactive: false }).then((h) => {
979
+ mountMap(host, { center: position, zoom: STREET_ZOOM, interactive: false }).then((handle) => {
981
980
  if (disposed) {
982
- h.dispose();
981
+ handle.dispose();
983
982
  return;
984
983
  }
985
- dispose = h.dispose;
986
- h.leaflet.marker(position).addTo(h.map);
984
+ dispose = handle.dispose;
985
+ handle.leaflet.marker(position).addTo(handle.map);
987
986
  }, () => {
988
987
  if (!disposed)
989
988
  onFailed();
@@ -1021,6 +1020,17 @@ function describeLocation(position) {
1021
1020
  const point = `${position.lat.toFixed(4)}, ${position.lng.toFixed(4)}`;
1022
1021
  return position.accuracy ? `${point} ±${position.accuracy} m` : point;
1023
1022
  }
1023
+ function locationPickerHint(state) {
1024
+ if (state.locating)
1025
+ return { key: "translate_location_locating", failed: false };
1026
+ if (state.deliveryFailed)
1027
+ return { key: "translate_location_send_failed", failed: true };
1028
+ if (state.locateFailed)
1029
+ return { key: "translate_location_locate_failed", failed: true };
1030
+ if (state.mapFailed)
1031
+ return { key: "translate_location_map_failed", failed: true };
1032
+ return { key: "translate_location_hint", failed: false };
1033
+ }
1024
1034
  // src/internal/client/src/chat/websocket.ts
1025
1035
  function wsBackoffDelay(attempt) {
1026
1036
  return Math.min(1000 * 2 ** (attempt - 1), 30000);
@@ -1417,9 +1427,10 @@ function firstViolation(entries, check) {
1417
1427
  return;
1418
1428
  }
1419
1429
  var URL_FUNCTION = /url\(([^)]*)\)/gi;
1420
- var IMAGE_FUNCTION = /\b(url|src|image|image-set|-webkit-image-set|cross-fade|element)\(/i;
1421
- var OTHER_IMAGE_FUNCTION = /\b(src|image|image-set|-webkit-image-set|cross-fade|element)\(/i;
1422
- var OTHER_IMAGE_FUNCTION_GLOBAL = /\b(src|image|image-set|-webkit-image-set|cross-fade|element)\([^)]*\)/gi;
1430
+ var OTHER_IMAGE_FUNCTION_NAMES = "src|image|image-set|-webkit-image-set|cross-fade|element";
1431
+ var IMAGE_FUNCTION = new RegExp(String.raw`\b(url|${OTHER_IMAGE_FUNCTION_NAMES})\(`, "i");
1432
+ var OTHER_IMAGE_FUNCTION = new RegExp(String.raw`\b(${OTHER_IMAGE_FUNCTION_NAMES})\(`, "i");
1433
+ var OTHER_IMAGE_FUNCTION_GLOBAL = new RegExp(String.raw`\b(${OTHER_IMAGE_FUNCTION_NAMES})\([^)]*\)`, "gi");
1423
1434
  var CSS_ESCAPE = /\\([0-9a-f]{1,6})\s?|\\(.)/gi;
1424
1435
  function decodeCssEscapes(text) {
1425
1436
  return text.replace(CSS_ESCAPE, (_, hex, literal) => {
@@ -1521,27 +1532,32 @@ ${source}`;
1521
1532
  return dispose;
1522
1533
  }
1523
1534
  };
1535
+ var PENDING_LABEL = {
1536
+ mermaid: "translate_media_pending_mermaid",
1537
+ "vega-lite": "translate_media_pending_vega_lite",
1538
+ map: "translate_media_pending_map"
1539
+ };
1540
+ function mediaPendingLabel(language) {
1541
+ return PENDING_LABEL[language] ?? "translate_media_pending";
1542
+ }
1524
1543
  function mediaLanguages(overrides) {
1525
1544
  return Object.keys({ ...builtIn, ...overrides });
1526
1545
  }
1527
- function renderMediaBlock(language, host, source, context, overrides) {
1528
- const renderer = overrides?.[language] ?? builtIn[language];
1529
- if (!renderer)
1530
- return Promise.reject(new Error(`No renderer for ${language}.`));
1531
- return renderer(host, source, context);
1532
- }
1533
1546
  function drawMediaBlock(host, options) {
1547
+ const { language, source, context, overrides, onError } = options;
1534
1548
  const slot = host.appendChild(document.createElement("div"));
1549
+ const renderer = overrides?.[language] ?? builtIn[language];
1535
1550
  let dispose;
1536
1551
  let cancelled = false;
1537
- renderMediaBlock(options.language, slot, options.source, options.context, options.overrides).then((teardown) => {
1552
+ const drawn = renderer ? renderer(slot, source, context) : Promise.reject(new Error(`No renderer for ${language}.`));
1553
+ drawn.then((teardown) => {
1538
1554
  if (cancelled)
1539
1555
  teardown();
1540
1556
  else
1541
1557
  dispose = teardown;
1542
1558
  }, (reason) => {
1543
1559
  if (!cancelled)
1544
- options.onError(reason instanceof Error ? reason.message : String(reason));
1560
+ onError(reason instanceof Error ? reason.message : String(reason));
1545
1561
  });
1546
1562
  return () => {
1547
1563
  cancelled = true;
@@ -1788,7 +1804,8 @@ var ar_default = {
1788
1804
  translate_media_source: "المصدر",
1789
1805
  translate_media_pending: "جارٍ الرسم",
1790
1806
  translate_image_unavailable: "الصورة غير متاحة",
1791
- translate_image_unavailable_alt: "الصورة غير متاحة: {{alt}}"
1807
+ translate_image_unavailable_alt: "الصورة غير متاحة: {{alt}}",
1808
+ translate_send: "إرسال"
1792
1809
  };
1793
1810
  // src/internal/client/src/i18n/en.json
1794
1811
  var en_default = {
@@ -1936,7 +1953,8 @@ var en_default = {
1936
1953
  translate_media_source: "Source",
1937
1954
  translate_media_pending: "Drawing",
1938
1955
  translate_image_unavailable: "Image unavailable",
1939
- translate_image_unavailable_alt: "Image unavailable: {{alt}}"
1956
+ translate_image_unavailable_alt: "Image unavailable: {{alt}}",
1957
+ translate_send: "Send"
1940
1958
  };
1941
1959
 
1942
1960
  // src/internal/client/src/i18n.ts
@@ -1950,6 +1968,9 @@ function translate(locale, key, params) {
1950
1968
  return value;
1951
1969
  return value.replace(/\{\{\s*(\w+)\s*\}\}/g, (match, name) => (name in params) ? String(params[name]) : match);
1952
1970
  }
1971
+ function pluralKey(count, one, other) {
1972
+ return count === 1 ? one : other;
1973
+ }
1953
1974
  // src/internal/client/src/format/deep-parse-json.ts
1954
1975
  function deepParseJson(value) {
1955
1976
  if (typeof value === "string") {
@@ -2193,7 +2214,8 @@ function createTurnLifecycle(options) {
2193
2214
  continue;
2194
2215
  if (!unansweredToolCalls(transcript).some((open) => open.id === call.id))
2195
2216
  return true;
2196
- if (await options.deliver(answer).then(() => true, () => false))
2217
+ const resent = await options.deliver(answer).then(() => true, () => false);
2218
+ if (resent)
2197
2219
  return true;
2198
2220
  }
2199
2221
  return false;
@@ -3103,11 +3125,8 @@ var ChatComposerComponent = class ChatComposerComponent2 {
3103
3125
  [class.cortex-widget__textarea--disabled]="chatService.isAgentWorking()"
3104
3126
  ></textarea>
3105
3127
  @if (chatService.isAgentWorking()) {
3106
- <!-- Stop button -->
3107
3128
  <button (click)="chatService.abort()" class="cortex-stop-btn">
3108
- <!-- Pulsing ring -->
3109
3129
  <span class="cortex-stop-btn__ring"></span>
3110
- <!-- Stop icon (rounded square) -->
3111
3130
  <svg width="12" height="12" viewBox="0 0 12 12" fill="none" class="cortex-stop-btn__icon">
3112
3131
  <rect x="1" y="1" width="10" height="10" rx="2.5" fill="currentColor" />
3113
3132
  </svg>
@@ -3115,7 +3134,6 @@ var ChatComposerComponent = class ChatComposerComponent2 {
3115
3134
  } @else {
3116
3135
  <div class="cortex-widget__input-actions">
3117
3136
  @if (attachmentsEnabled()) {
3118
- <!-- Attach button -->
3119
3137
  <button
3120
3138
  type="button"
3121
3139
  (click)="fileInput.click()"
@@ -3142,7 +3160,6 @@ var ChatComposerComponent = class ChatComposerComponent2 {
3142
3160
  />
3143
3161
  }
3144
3162
 
3145
- <!-- Send button -->
3146
3163
  <button
3147
3164
  (click)="send()"
3148
3165
  class="cortex-widget__send-btn"
@@ -3229,11 +3246,8 @@ i0.ɵɵngDeclareClassMetadata({
3229
3246
  [class.cortex-widget__textarea--disabled]="chatService.isAgentWorking()"
3230
3247
  ></textarea>
3231
3248
  @if (chatService.isAgentWorking()) {
3232
- <!-- Stop button -->
3233
3249
  <button (click)="chatService.abort()" class="cortex-stop-btn">
3234
- <!-- Pulsing ring -->
3235
3250
  <span class="cortex-stop-btn__ring"></span>
3236
- <!-- Stop icon (rounded square) -->
3237
3251
  <svg width="12" height="12" viewBox="0 0 12 12" fill="none" class="cortex-stop-btn__icon">
3238
3252
  <rect x="1" y="1" width="10" height="10" rx="2.5" fill="currentColor" />
3239
3253
  </svg>
@@ -3241,7 +3255,6 @@ i0.ɵɵngDeclareClassMetadata({
3241
3255
  } @else {
3242
3256
  <div class="cortex-widget__input-actions">
3243
3257
  @if (attachmentsEnabled()) {
3244
- <!-- Attach button -->
3245
3258
  <button
3246
3259
  type="button"
3247
3260
  (click)="fileInput.click()"
@@ -3268,7 +3281,6 @@ i0.ɵɵngDeclareClassMetadata({
3268
3281
  />
3269
3282
  }
3270
3283
 
3271
- <!-- Send button -->
3272
3284
  <button
3273
3285
  (click)="send()"
3274
3286
  class="cortex-widget__send-btn"
@@ -3353,14 +3365,12 @@ var ChatHeaderComponent = class ChatHeaderComponent2 {
3353
3365
  </svg>
3354
3366
  </button>
3355
3367
 
3356
- <!-- Title -->
3357
3368
  <div class="cortex-widget__chat-title-wrap">
3358
3369
  <p class="cortex-widget__chat-title">
3359
3370
  {{ chatService.selectedThread()?.title ?? agentName() ?? ('translate_new_chat' | translate) }}
3360
3371
  </p>
3361
3372
  </div>
3362
3373
 
3363
- <!-- Debug toggle -->
3364
3374
  @if (config().showDebugButton) {
3365
3375
  <button
3366
3376
  (click)="toggleDebug.emit()"
@@ -3372,7 +3382,6 @@ var ChatHeaderComponent = class ChatHeaderComponent2 {
3372
3382
  </button>
3373
3383
  }
3374
3384
 
3375
- <!-- History button -->
3376
3385
  <button
3377
3386
  type="button"
3378
3387
  (click)="openHistory.emit()"
@@ -3425,14 +3434,12 @@ i0.ɵɵngDeclareClassMetadata({
3425
3434
  </svg>
3426
3435
  </button>
3427
3436
 
3428
- <!-- Title -->
3429
3437
  <div class="cortex-widget__chat-title-wrap">
3430
3438
  <p class="cortex-widget__chat-title">
3431
3439
  {{ chatService.selectedThread()?.title ?? agentName() ?? ('translate_new_chat' | translate) }}
3432
3440
  </p>
3433
3441
  </div>
3434
3442
 
3435
- <!-- Debug toggle -->
3436
3443
  @if (config().showDebugButton) {
3437
3444
  <button
3438
3445
  (click)="toggleDebug.emit()"
@@ -3444,7 +3451,6 @@ i0.ɵɵngDeclareClassMetadata({
3444
3451
  </button>
3445
3452
  }
3446
3453
 
3447
- <!-- History button -->
3448
3454
  <button
3449
3455
  type="button"
3450
3456
  (click)="openHistory.emit()"
@@ -3490,10 +3496,9 @@ i0.ɵɵngDeclareClassMetadata({
3490
3496
  });
3491
3497
  var ChatLandingComponent = class ChatLandingComponent2 {
3492
3498
  threadSelected = output();
3493
- config = inject(CORTEX_CONFIG);
3494
3499
  chatService = inject(CortexChatService);
3495
- locale = inject(CORTEX_LOCALE);
3496
3500
  threadService = inject(CortexThreadService);
3501
+ locale = inject(CORTEX_LOCALE);
3497
3502
  greeting = computed(() => localized(this.chatService.capabilities()?.greeting, this.locale()) || null, ...ngDevMode ? [{ debugName: "greeting" }] : []);
3498
3503
  suggestions = computed(() => localized(this.chatService.capabilities()?.suggestions, this.locale()), ...ngDevMode ? [{ debugName: "suggestions" }] : []);
3499
3504
  ready = computed(() => this.chatService.capabilities() !== undefined, ...ngDevMode ? [{ debugName: "ready" }] : []);
@@ -4235,23 +4240,13 @@ var JsonTreeComponent = class JsonTreeComponent2 {
4235
4240
  data = input.required(...ngDevMode ? [{ debugName: "data" }] : []);
4236
4241
  expandDepth = input(1, ...ngDevMode ? [{ debugName: "expandDepth" }] : []);
4237
4242
  parsedData = computed(() => deepParseJson(this.data()), ...ngDevMode ? [{ debugName: "parsedData" }] : []);
4238
- collapsedPaths = /* @__PURE__ */ new Set;
4239
- userToggled = /* @__PURE__ */ new Set;
4243
+ describe = describeJsonValue;
4244
+ userToggled = /* @__PURE__ */ new Map;
4240
4245
  isCollapsed(path, depth) {
4241
- if (this.userToggled.has(path))
4242
- return this.collapsedPaths.has(path);
4243
- return depth >= this.expandDepth();
4246
+ return this.userToggled.get(path) ?? depth >= this.expandDepth();
4244
4247
  }
4245
4248
  toggle(path, depth) {
4246
- const collapsed = this.isCollapsed(path, depth);
4247
- this.userToggled.add(path);
4248
- if (collapsed)
4249
- this.collapsedPaths.delete(path);
4250
- else
4251
- this.collapsedPaths.add(path);
4252
- }
4253
- describe(value, path) {
4254
- return describeJsonValue(value, path);
4249
+ this.userToggled.set(path, !this.isCollapsed(path, depth));
4255
4250
  }
4256
4251
  static ɵfac = i0.ɵɵngDeclareFactory({
4257
4252
  minVersion: "12.0.0",
@@ -4857,10 +4852,7 @@ i0.ɵɵngDeclareClassMetadata({
4857
4852
  type: MarkedPipe,
4858
4853
  decorators: [{
4859
4854
  type: Pipe,
4860
- args: [{
4861
- name: "marked",
4862
- standalone: true
4863
- }]
4855
+ args: [{ name: "marked" }]
4864
4856
  }]
4865
4857
  });
4866
4858
  var AttachmentImageComponent = class AttachmentImageComponent2 {
@@ -5020,11 +5012,6 @@ i0.ɵɵngDeclareClassMetadata({
5020
5012
  }]
5021
5013
  }
5022
5014
  });
5023
- var PENDING_LABEL = {
5024
- mermaid: "translate_media_pending_mermaid",
5025
- "vega-lite": "translate_media_pending_vega_lite",
5026
- map: "translate_media_pending_map"
5027
- };
5028
5015
  var MediaBlockHeadComponent = class MediaBlockHeadComponent2 {
5029
5016
  language = input.required(...ngDevMode ? [{ debugName: "language" }] : []);
5030
5017
  source = input.required(...ngDevMode ? [{ debugName: "source" }] : []);
@@ -5034,7 +5021,7 @@ var MediaBlockHeadComponent = class MediaBlockHeadComponent2 {
5034
5021
  sourceShown = input.required(...ngDevMode ? [{ debugName: "sourceShown" }] : []);
5035
5022
  canToggleSource = input.required(...ngDevMode ? [{ debugName: "canToggleSource" }] : []);
5036
5023
  toggleSource = output();
5037
- pendingLabel = computed(() => PENDING_LABEL[this.language()] ?? "translate_media_pending", ...ngDevMode ? [{ debugName: "pendingLabel" }] : []);
5024
+ pendingLabel = computed(() => mediaPendingLabel(this.language()), ...ngDevMode ? [{ debugName: "pendingLabel" }] : []);
5038
5025
  static ɵfac = i0.ɵɵngDeclareFactory({
5039
5026
  minVersion: "12.0.0",
5040
5027
  version: "22.2.0",
@@ -5509,6 +5496,9 @@ var MessageTextPartComponent = class MessageTextPartComponent2 {
5509
5496
  streaming = input(false, ...ngDevMode ? [{ debugName: "streaming" }] : []);
5510
5497
  debugMode = input(false, ...ngDevMode ? [{ debugName: "debugMode" }] : []);
5511
5498
  attachments = input([], ...ngDevMode ? [{ debugName: "attachments" }] : []);
5499
+ config = inject(CORTEX_CONFIG);
5500
+ smoother = null;
5501
+ isFirstRender = true;
5512
5502
  displayedText = signal("", ...ngDevMode ? [{ debugName: "displayedText" }] : []);
5513
5503
  fading = signal([], ...ngDevMode ? [{ debugName: "fading" }] : []);
5514
5504
  segments = computed(() => this.role() === "assistant" ? segmentMessageText(this.displayedText(), mediaLanguages(this.config().mediaRenderers)) : [{
@@ -5519,9 +5509,6 @@ var MessageTextPartComponent = class MessageTextPartComponent2 {
5519
5509
  attachmentFor(id) {
5520
5510
  return this.attachments().find((attachment) => attachment.id.toLowerCase() === id);
5521
5511
  }
5522
- config = inject(CORTEX_CONFIG);
5523
- smoother = null;
5524
- isFirstRender = true;
5525
5512
  constructor() {
5526
5513
  effect(() => {
5527
5514
  const part = this.textPart();
@@ -5533,31 +5520,28 @@ var MessageTextPartComponent = class MessageTextPartComponent2 {
5533
5520
  this.isFirstRender = false;
5534
5521
  return;
5535
5522
  }
5523
+ const smoother = this.ensureSmoother();
5536
5524
  if (this.isFirstRender) {
5537
- this.ensureSmoother();
5538
- this.smoother.seed(part.content);
5539
5525
  this.isFirstRender = false;
5526
+ smoother.seed(part.content);
5540
5527
  return;
5541
5528
  }
5542
- this.isFirstRender = false;
5543
- this.ensureSmoother();
5544
- this.smoother.update(part.content, false);
5529
+ smoother.update(part.content, false);
5545
5530
  });
5546
5531
  }
5547
5532
  ngOnDestroy() {
5548
5533
  this.destroySmoother();
5549
5534
  }
5550
5535
  destroySmoother() {
5551
- if (this.smoother) {
5552
- this.smoother.destroy();
5553
- this.smoother = null;
5554
- }
5536
+ this.smoother?.destroy();
5537
+ this.smoother = null;
5555
5538
  }
5556
5539
  ensureSmoother() {
5557
- if (this.smoother)
5558
- return;
5559
- this.smoother = new StreamTextSmoother((text, fading) => this.show(text, fading));
5560
- this.smoother.seed(this.displayedText());
5540
+ if (!this.smoother) {
5541
+ this.smoother = new StreamTextSmoother((text, fading) => this.show(text, fading));
5542
+ this.smoother.seed(this.displayedText());
5543
+ }
5544
+ return this.smoother;
5561
5545
  }
5562
5546
  show(text, fading) {
5563
5547
  this.displayedText.set(text);
@@ -6012,10 +5996,7 @@ i0.ɵɵngDeclareClassMetadata({
6012
5996
  type: HighlightPipe,
6013
5997
  decorators: [{
6014
5998
  type: Pipe,
6015
- args: [{
6016
- name: "highlight",
6017
- standalone: true
6018
- }]
5999
+ args: [{ name: "highlight" }]
6019
6000
  }]
6020
6001
  });
6021
6002
  var MessageToolCallOutcomeComponent = class MessageToolCallOutcomeComponent2 {
@@ -6962,33 +6943,7 @@ var LocationPickerComponent = class LocationPickerComponent2 {
6962
6943
  center = input.required(...ngDevMode ? [{ debugName: "center" }] : []);
6963
6944
  submit = input.required(...ngDevMode ? [{ debugName: "submit" }] : []);
6964
6945
  picked = signal(LOCATION_PICKER_IDLE, ...ngDevMode ? [{ debugName: "picked" }] : []);
6965
- hint = computed(() => {
6966
- const state = this.picked();
6967
- if (state.locating)
6968
- return {
6969
- key: "translate_location_locating",
6970
- failed: false
6971
- };
6972
- if (state.deliveryFailed)
6973
- return {
6974
- key: "translate_location_send_failed",
6975
- failed: true
6976
- };
6977
- if (state.locateFailed)
6978
- return {
6979
- key: "translate_location_locate_failed",
6980
- failed: true
6981
- };
6982
- if (state.mapFailed)
6983
- return {
6984
- key: "translate_location_map_failed",
6985
- failed: true
6986
- };
6987
- return {
6988
- key: "translate_location_hint",
6989
- failed: false
6990
- };
6991
- }, ...ngDevMode ? [{ debugName: "hint" }] : []);
6946
+ hint = computed(() => locationPickerHint(this.picked()), ...ngDevMode ? [{ debugName: "hint" }] : []);
6992
6947
  describe = describeLocation;
6993
6948
  host = viewChild.required("host", ...ngDevMode ? [{ debugName: "host" }] : []);
6994
6949
  picker;
@@ -7446,12 +7401,13 @@ i0.ɵɵngDeclareClassMetadata({
7446
7401
  }]
7447
7402
  }
7448
7403
  });
7449
- var BUILT_IN_TOOL_COMPONENTS = { [REQUEST_LOCATION_TOOL]: LocationInputComponent };
7404
+ var BUILT_IN_TOOL_COMPONENTS = /* @__PURE__ */ new Map([[REQUEST_LOCATION_TOOL, LocationInputComponent]]);
7450
7405
  var MessageToolCallAnimatedComponent = class MessageToolCallAnimatedComponent2 {
7451
7406
  message = input.required(...ngDevMode ? [{ debugName: "message" }] : []);
7452
7407
  toolCallPart = input.required(...ngDevMode ? [{ debugName: "toolCallPart" }] : []);
7453
7408
  config = inject(CORTEX_CONFIG);
7454
7409
  locale = inject(CORTEX_LOCALE);
7410
+ chatService = inject(CortexChatService);
7455
7411
  mountedComponent = computed(() => {
7456
7412
  const part = this.toolCallPart();
7457
7413
  const setOutput = (output2) => this.chatService.addToolResult(part.id, part.name, output2);
@@ -7465,7 +7421,7 @@ var MessageToolCallAnimatedComponent = class MessageToolCallAnimatedComponent2 {
7465
7421
  setOutput
7466
7422
  }
7467
7423
  };
7468
- const builtIn2 = this.owed() || isSettledToolState(part.state) ? BUILT_IN_TOOL_COMPONENTS[part.name] : undefined;
7424
+ const builtIn2 = this.owed() || isSettledToolState(part.state) ? BUILT_IN_TOOL_COMPONENTS.get(part.name) : undefined;
7469
7425
  return builtIn2 ? {
7470
7426
  type: builtIn2,
7471
7427
  inputs: {
@@ -7480,9 +7436,7 @@ var MessageToolCallAnimatedComponent = class MessageToolCallAnimatedComponent2 {
7480
7436
  approvalRequested = computed(() => this.toolCallPart().state === "approval-requested" && !this.chatService.isAgentWorking(), ...ngDevMode ? [{ debugName: "approvalRequested" }] : []);
7481
7437
  prompt = computed(() => approvalPrompt(this.toolCallPart(), this.locale()) ?? translate(this.locale(), "translate_approval_prompt"), ...ngDevMode ? [{ debugName: "prompt" }] : []);
7482
7438
  respond(approved) {
7483
- const part = this.toolCallPart();
7484
- const approvalId = part.approval?.id ?? `approval_${part.id}`;
7485
- this.chatService.respondToApproval(approvalId, approved);
7439
+ this.chatService.respondToApproval(approvalIdOf(this.toolCallPart()), approved);
7486
7440
  }
7487
7441
  animation = computed(() => toolCallAnimation(this.toolCallPart()), ...ngDevMode ? [{ debugName: "animation" }] : []);
7488
7442
  animState = computed(() => this.animation().state, ...ngDevMode ? [{ debugName: "animState" }] : []);
@@ -7494,7 +7448,6 @@ var MessageToolCallAnimatedComponent = class MessageToolCallAnimatedComponent2 {
7494
7448
  const count2 = this.animation().rowCount;
7495
7449
  return count2 === undefined ? undefined : translate(this.locale(), "translate_rows_read", { count: count2 });
7496
7450
  }, ...ngDevMode ? [{ debugName: "rowsLabel" }] : []);
7497
- chatService = inject(CortexChatService);
7498
7451
  static ɵfac = i0.ɵɵngDeclareFactory({
7499
7452
  minVersion: "12.0.0",
7500
7453
  version: "22.2.0",
@@ -8512,7 +8465,7 @@ var MessageBodyComponent = class MessageBodyComponent2 {
8512
8465
  const mark = this.fold()?.get(part);
8513
8466
  if (mark?.kind !== "more")
8514
8467
  return;
8515
- const key = mark.count === 1 ? "translate_one_more_step" : "translate_n_more_steps";
8468
+ const key = pluralKey(mark.count, "translate_one_more_step", "translate_n_more_steps");
8516
8469
  return {
8517
8470
  runId: mark.runId,
8518
8471
  count: mark.count,
@@ -9456,7 +9409,7 @@ var ThreadListComponent = class ThreadListComponent2 {
9456
9409
  this.chatService.deleteThread(threadId).subscribe();
9457
9410
  }
9458
9411
  countKey(count2) {
9459
- return count2 === 1 ? "translate_one_conversation" : "translate_n_conversations";
9412
+ return pluralKey(count2, "translate_one_conversation", "translate_n_conversations");
9460
9413
  }
9461
9414
  relativeTime(iso) {
9462
9415
  return timeLabel(iso, this.locale());
@@ -9484,7 +9437,6 @@ var ThreadListComponent = class ThreadListComponent2 {
9484
9437
  template: `@let threads = threadService.threads();
9485
9438
  @let threadCount = threads?.length ?? 0;
9486
9439
 
9487
- <!-- Threads header -->
9488
9440
  <div class="cortex-widget__threads-header">
9489
9441
  <!-- Back to chat (helper mode; full mode hides it, the sidebar is always visible) -->
9490
9442
  <button
@@ -9527,10 +9479,9 @@ var ThreadListComponent = class ThreadListComponent2 {
9527
9479
  </button>
9528
9480
  </div>
9529
9481
 
9530
- <!-- Threads list -->
9531
9482
  <div class="cortex-widget__threads-list">
9532
- <!-- Threads loading skeleton. The three states are siblings rather than an
9533
- if/else ladder so the row markup below sits one level shallower. -->
9483
+ <!-- The loading, listed and empty states are siblings rather than an if/else
9484
+ ladder, so the row markup sits one level shallower. -->
9534
9485
  @if (threads === undefined) {
9535
9486
  @for (i of [1, 2, 3, 4]; track i) {
9536
9487
  <div class="cortex-widget__thread-skeleton">
@@ -9552,7 +9503,6 @@ var ThreadListComponent = class ThreadListComponent2 {
9552
9503
  class="cortex-widget__thread-item"
9553
9504
  [class.cortex-widget__thread-item--active]="isActive"
9554
9505
  >
9555
- <!-- Thread icon -->
9556
9506
  <div class="cortex-widget__thread-icon" [class.cortex-widget__thread-icon--active]="isActive">
9557
9507
  <svg width="14" height="14" viewBox="0 0 16 16" fill="none">
9558
9508
  <!-- Rounded speech bubble with a tail, on the shared 16x16 icon grid. -->
@@ -9566,7 +9516,6 @@ var ThreadListComponent = class ThreadListComponent2 {
9566
9516
  </svg>
9567
9517
  </div>
9568
9518
 
9569
- <!-- Thread info -->
9570
9519
  <div class="cortex-widget__thread-info">
9571
9520
  <div class="cortex-widget__thread-title-row">
9572
9521
  <p
@@ -9593,7 +9542,6 @@ var ThreadListComponent = class ThreadListComponent2 {
9593
9542
  }
9594
9543
  </div>
9595
9544
 
9596
- <!-- Delete button -->
9597
9545
  <button
9598
9546
  (click)="deleteThread($event, thread.id)"
9599
9547
  class="cortex-widget__thread-delete"
@@ -9609,7 +9557,6 @@ var ThreadListComponent = class ThreadListComponent2 {
9609
9557
  </svg>
9610
9558
  </button>
9611
9559
 
9612
- <!-- Arrow -->
9613
9560
  <svg
9614
9561
  class="cortex-widget__thread-arrow"
9615
9562
  [class.cortex-widget__thread-arrow--active]="isActive"
@@ -9688,7 +9635,6 @@ i0.ɵɵngDeclareClassMetadata({
9688
9635
  template: `@let threads = threadService.threads();
9689
9636
  @let threadCount = threads?.length ?? 0;
9690
9637
 
9691
- <!-- Threads header -->
9692
9638
  <div class="cortex-widget__threads-header">
9693
9639
  <!-- Back to chat (helper mode; full mode hides it, the sidebar is always visible) -->
9694
9640
  <button
@@ -9731,10 +9677,9 @@ i0.ɵɵngDeclareClassMetadata({
9731
9677
  </button>
9732
9678
  </div>
9733
9679
 
9734
- <!-- Threads list -->
9735
9680
  <div class="cortex-widget__threads-list">
9736
- <!-- Threads loading skeleton. The three states are siblings rather than an
9737
- if/else ladder so the row markup below sits one level shallower. -->
9681
+ <!-- The loading, listed and empty states are siblings rather than an if/else
9682
+ ladder, so the row markup sits one level shallower. -->
9738
9683
  @if (threads === undefined) {
9739
9684
  @for (i of [1, 2, 3, 4]; track i) {
9740
9685
  <div class="cortex-widget__thread-skeleton">
@@ -9756,7 +9701,6 @@ i0.ɵɵngDeclareClassMetadata({
9756
9701
  class="cortex-widget__thread-item"
9757
9702
  [class.cortex-widget__thread-item--active]="isActive"
9758
9703
  >
9759
- <!-- Thread icon -->
9760
9704
  <div class="cortex-widget__thread-icon" [class.cortex-widget__thread-icon--active]="isActive">
9761
9705
  <svg width="14" height="14" viewBox="0 0 16 16" fill="none">
9762
9706
  <!-- Rounded speech bubble with a tail, on the shared 16x16 icon grid. -->
@@ -9770,7 +9714,6 @@ i0.ɵɵngDeclareClassMetadata({
9770
9714
  </svg>
9771
9715
  </div>
9772
9716
 
9773
- <!-- Thread info -->
9774
9717
  <div class="cortex-widget__thread-info">
9775
9718
  <div class="cortex-widget__thread-title-row">
9776
9719
  <p
@@ -9797,7 +9740,6 @@ i0.ɵɵngDeclareClassMetadata({
9797
9740
  }
9798
9741
  </div>
9799
9742
 
9800
- <!-- Delete button -->
9801
9743
  <button
9802
9744
  (click)="deleteThread($event, thread.id)"
9803
9745
  class="cortex-widget__thread-delete"
@@ -9813,7 +9755,6 @@ i0.ɵɵngDeclareClassMetadata({
9813
9755
  </svg>
9814
9756
  </button>
9815
9757
 
9816
- <!-- Arrow -->
9817
9758
  <svg
9818
9759
  class="cortex-widget__thread-arrow"
9819
9760
  [class.cortex-widget__thread-arrow--active]="isActive"
@@ -10003,7 +9944,6 @@ var CortexChatWidgetComponent = class CortexChatWidgetComponent2 {
10003
9944
  (dragover)="onWidgetDragOver($event)"
10004
9945
  (drop)="onWidgetDrop($event)"
10005
9946
  >
10006
- <!-- SCREEN 1: THREADS -->
10007
9947
  <cortex-thread-list
10008
9948
  class="cortex-widget__screen"
10009
9949
  [class.cortex-widget__screen--active]="screen() === 'threads'"
@@ -10013,7 +9953,6 @@ var CortexChatWidgetComponent = class CortexChatWidgetComponent2 {
10013
9953
  (backRequested)="closeHistory()"
10014
9954
  />
10015
9955
 
10016
- <!-- SCREEN 2: CHAT -->
10017
9956
  <div
10018
9957
  class="cortex-widget__screen"
10019
9958
  [class.cortex-widget__screen--active]="screen() === 'chat'"
@@ -10033,11 +9972,9 @@ var CortexChatWidgetComponent = class CortexChatWidgetComponent2 {
10033
9972
  } @else if (chatService.isLoadingMessages() && !chatService.isAgentWorking()) {
10034
9973
  <cortex-messages-skeleton />
10035
9974
  } @else {
10036
- <!-- Messages area -->
10037
9975
  <cortex-message-list class="cortex-widget__messages" [debugMode]="debugMode()" />
10038
9976
  }
10039
9977
 
10040
- <!-- Agent working indicator -->
10041
9978
  @if (chatService.isAgentWorking() && !chatService.hasPendingToolCalls()) {
10042
9979
  <div class="cortex-widget__working">
10043
9980
  <div class="cortex-widget__working-dots">
@@ -10166,7 +10103,6 @@ i0.ɵɵngDeclareClassMetadata({
10166
10103
  (dragover)="onWidgetDragOver($event)"
10167
10104
  (drop)="onWidgetDrop($event)"
10168
10105
  >
10169
- <!-- SCREEN 1: THREADS -->
10170
10106
  <cortex-thread-list
10171
10107
  class="cortex-widget__screen"
10172
10108
  [class.cortex-widget__screen--active]="screen() === 'threads'"
@@ -10176,7 +10112,6 @@ i0.ɵɵngDeclareClassMetadata({
10176
10112
  (backRequested)="closeHistory()"
10177
10113
  />
10178
10114
 
10179
- <!-- SCREEN 2: CHAT -->
10180
10115
  <div
10181
10116
  class="cortex-widget__screen"
10182
10117
  [class.cortex-widget__screen--active]="screen() === 'chat'"
@@ -10196,11 +10131,9 @@ i0.ɵɵngDeclareClassMetadata({
10196
10131
  } @else if (chatService.isLoadingMessages() && !chatService.isAgentWorking()) {
10197
10132
  <cortex-messages-skeleton />
10198
10133
  } @else {
10199
- <!-- Messages area -->
10200
10134
  <cortex-message-list class="cortex-widget__messages" [debugMode]="debugMode()" />
10201
10135
  }
10202
10136
 
10203
- <!-- Agent working indicator -->
10204
10137
  @if (chatService.isAgentWorking() && !chatService.hasPendingToolCalls()) {
10205
10138
  <div class="cortex-widget__working">
10206
10139
  <div class="cortex-widget__working-dots">
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@m6d/cortex-angular",
3
- "version": "0.3.0",
3
+ "version": "0.4.1",
4
4
  "description": "Reusable AI agent chat UI library for Angular",
5
5
  "license": "MIT",
6
6
  "sideEffects": false,
@@ -16,11 +16,11 @@ declare const ATTACHMENT_STATUSES: readonly [
16
16
  "failed",
17
17
  "skipped"
18
18
  ];
19
+ export type AttachmentStatus = (typeof ATTACHMENT_STATUSES)[number];
19
20
  declare const ATTACHMENT_ORIGINS: readonly [
20
21
  "upload",
21
22
  "tool"
22
23
  ];
23
- export type AttachmentStatus = (typeof ATTACHMENT_STATUSES)[number];
24
24
  export type AttachmentOrigin = (typeof ATTACHMENT_ORIGINS)[number];
25
25
  export type AttachmentSummary = {
26
26
  id: string;
@@ -170,11 +170,11 @@ declare const ATTACHMENT_STATUSES$1: readonly [
170
170
  "failed",
171
171
  "skipped"
172
172
  ];
173
+ type AttachmentStatus$1 = (typeof ATTACHMENT_STATUSES$1)[number];
173
174
  declare const ATTACHMENT_ORIGINS$1: readonly [
174
175
  "upload",
175
176
  "tool"
176
177
  ];
177
- type AttachmentStatus$1 = (typeof ATTACHMENT_STATUSES$1)[number];
178
178
  type AttachmentOrigin$1 = (typeof ATTACHMENT_ORIGINS$1)[number];
179
179
  export type AttachmentSummary$1 = {
180
180
  id: string;
@@ -269,7 +269,7 @@ declare class CortexChatService {
269
269
  * forgotten first.
270
270
  */
271
271
  private loadCapabilities;
272
- get events$(): Observable<"onFinish" | "onError" | "onThreadSelected" | "onSend">;
272
+ get events$(): Observable<"onError" | "onFinish" | "onThreadSelected" | "onSend">;
273
273
  selectThread(thread: ThreadSummary, options?: {
274
274
  skipLoadingMessages?: boolean;
275
275
  }): Observable<ThreadSummary>;
@@ -315,6 +315,7 @@ declare class CortexChatService {
315
315
  static ɵfac: i0.ɵɵFactoryDeclaration<CortexChatService, never>;
316
316
  static ɵprov: i0.ɵɵInjectableDeclaration<any>;
317
317
  }
318
+ /** The chat widget: the thread list, the open conversation and its composer, for the agent `config` points at. */
318
319
  export declare class CortexChatWidgetComponent implements OnInit {
319
320
  readonly config: import("@angular/core").InputSignal<CortexAngularConfig>;
320
321
  protected readonly debugMode: import("@angular/core").WritableSignal<boolean>;