@m6d/cortex-angular 0.3.0 → 0.4.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.
@@ -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;
@@ -1950,6 +1966,9 @@ function translate(locale, key, params) {
1950
1966
  return value;
1951
1967
  return value.replace(/\{\{\s*(\w+)\s*\}\}/g, (match, name) => (name in params) ? String(params[name]) : match);
1952
1968
  }
1969
+ function pluralKey(count, one, other) {
1970
+ return count === 1 ? one : other;
1971
+ }
1953
1972
  // src/internal/client/src/format/deep-parse-json.ts
1954
1973
  function deepParseJson(value) {
1955
1974
  if (typeof value === "string") {
@@ -2193,7 +2212,8 @@ function createTurnLifecycle(options) {
2193
2212
  continue;
2194
2213
  if (!unansweredToolCalls(transcript).some((open) => open.id === call.id))
2195
2214
  return true;
2196
- if (await options.deliver(answer).then(() => true, () => false))
2215
+ const resent = await options.deliver(answer).then(() => true, () => false);
2216
+ if (resent)
2197
2217
  return true;
2198
2218
  }
2199
2219
  return false;
@@ -3103,11 +3123,8 @@ var ChatComposerComponent = class ChatComposerComponent2 {
3103
3123
  [class.cortex-widget__textarea--disabled]="chatService.isAgentWorking()"
3104
3124
  ></textarea>
3105
3125
  @if (chatService.isAgentWorking()) {
3106
- <!-- Stop button -->
3107
3126
  <button (click)="chatService.abort()" class="cortex-stop-btn">
3108
- <!-- Pulsing ring -->
3109
3127
  <span class="cortex-stop-btn__ring"></span>
3110
- <!-- Stop icon (rounded square) -->
3111
3128
  <svg width="12" height="12" viewBox="0 0 12 12" fill="none" class="cortex-stop-btn__icon">
3112
3129
  <rect x="1" y="1" width="10" height="10" rx="2.5" fill="currentColor" />
3113
3130
  </svg>
@@ -3115,7 +3132,6 @@ var ChatComposerComponent = class ChatComposerComponent2 {
3115
3132
  } @else {
3116
3133
  <div class="cortex-widget__input-actions">
3117
3134
  @if (attachmentsEnabled()) {
3118
- <!-- Attach button -->
3119
3135
  <button
3120
3136
  type="button"
3121
3137
  (click)="fileInput.click()"
@@ -3142,7 +3158,6 @@ var ChatComposerComponent = class ChatComposerComponent2 {
3142
3158
  />
3143
3159
  }
3144
3160
 
3145
- <!-- Send button -->
3146
3161
  <button
3147
3162
  (click)="send()"
3148
3163
  class="cortex-widget__send-btn"
@@ -3229,11 +3244,8 @@ i0.ɵɵngDeclareClassMetadata({
3229
3244
  [class.cortex-widget__textarea--disabled]="chatService.isAgentWorking()"
3230
3245
  ></textarea>
3231
3246
  @if (chatService.isAgentWorking()) {
3232
- <!-- Stop button -->
3233
3247
  <button (click)="chatService.abort()" class="cortex-stop-btn">
3234
- <!-- Pulsing ring -->
3235
3248
  <span class="cortex-stop-btn__ring"></span>
3236
- <!-- Stop icon (rounded square) -->
3237
3249
  <svg width="12" height="12" viewBox="0 0 12 12" fill="none" class="cortex-stop-btn__icon">
3238
3250
  <rect x="1" y="1" width="10" height="10" rx="2.5" fill="currentColor" />
3239
3251
  </svg>
@@ -3241,7 +3253,6 @@ i0.ɵɵngDeclareClassMetadata({
3241
3253
  } @else {
3242
3254
  <div class="cortex-widget__input-actions">
3243
3255
  @if (attachmentsEnabled()) {
3244
- <!-- Attach button -->
3245
3256
  <button
3246
3257
  type="button"
3247
3258
  (click)="fileInput.click()"
@@ -3268,7 +3279,6 @@ i0.ɵɵngDeclareClassMetadata({
3268
3279
  />
3269
3280
  }
3270
3281
 
3271
- <!-- Send button -->
3272
3282
  <button
3273
3283
  (click)="send()"
3274
3284
  class="cortex-widget__send-btn"
@@ -3353,14 +3363,12 @@ var ChatHeaderComponent = class ChatHeaderComponent2 {
3353
3363
  </svg>
3354
3364
  </button>
3355
3365
 
3356
- <!-- Title -->
3357
3366
  <div class="cortex-widget__chat-title-wrap">
3358
3367
  <p class="cortex-widget__chat-title">
3359
3368
  {{ chatService.selectedThread()?.title ?? agentName() ?? ('translate_new_chat' | translate) }}
3360
3369
  </p>
3361
3370
  </div>
3362
3371
 
3363
- <!-- Debug toggle -->
3364
3372
  @if (config().showDebugButton) {
3365
3373
  <button
3366
3374
  (click)="toggleDebug.emit()"
@@ -3372,7 +3380,6 @@ var ChatHeaderComponent = class ChatHeaderComponent2 {
3372
3380
  </button>
3373
3381
  }
3374
3382
 
3375
- <!-- History button -->
3376
3383
  <button
3377
3384
  type="button"
3378
3385
  (click)="openHistory.emit()"
@@ -3425,14 +3432,12 @@ i0.ɵɵngDeclareClassMetadata({
3425
3432
  </svg>
3426
3433
  </button>
3427
3434
 
3428
- <!-- Title -->
3429
3435
  <div class="cortex-widget__chat-title-wrap">
3430
3436
  <p class="cortex-widget__chat-title">
3431
3437
  {{ chatService.selectedThread()?.title ?? agentName() ?? ('translate_new_chat' | translate) }}
3432
3438
  </p>
3433
3439
  </div>
3434
3440
 
3435
- <!-- Debug toggle -->
3436
3441
  @if (config().showDebugButton) {
3437
3442
  <button
3438
3443
  (click)="toggleDebug.emit()"
@@ -3444,7 +3449,6 @@ i0.ɵɵngDeclareClassMetadata({
3444
3449
  </button>
3445
3450
  }
3446
3451
 
3447
- <!-- History button -->
3448
3452
  <button
3449
3453
  type="button"
3450
3454
  (click)="openHistory.emit()"
@@ -3490,10 +3494,9 @@ i0.ɵɵngDeclareClassMetadata({
3490
3494
  });
3491
3495
  var ChatLandingComponent = class ChatLandingComponent2 {
3492
3496
  threadSelected = output();
3493
- config = inject(CORTEX_CONFIG);
3494
3497
  chatService = inject(CortexChatService);
3495
- locale = inject(CORTEX_LOCALE);
3496
3498
  threadService = inject(CortexThreadService);
3499
+ locale = inject(CORTEX_LOCALE);
3497
3500
  greeting = computed(() => localized(this.chatService.capabilities()?.greeting, this.locale()) || null, ...ngDevMode ? [{ debugName: "greeting" }] : []);
3498
3501
  suggestions = computed(() => localized(this.chatService.capabilities()?.suggestions, this.locale()), ...ngDevMode ? [{ debugName: "suggestions" }] : []);
3499
3502
  ready = computed(() => this.chatService.capabilities() !== undefined, ...ngDevMode ? [{ debugName: "ready" }] : []);
@@ -4235,23 +4238,13 @@ var JsonTreeComponent = class JsonTreeComponent2 {
4235
4238
  data = input.required(...ngDevMode ? [{ debugName: "data" }] : []);
4236
4239
  expandDepth = input(1, ...ngDevMode ? [{ debugName: "expandDepth" }] : []);
4237
4240
  parsedData = computed(() => deepParseJson(this.data()), ...ngDevMode ? [{ debugName: "parsedData" }] : []);
4238
- collapsedPaths = /* @__PURE__ */ new Set;
4239
- userToggled = /* @__PURE__ */ new Set;
4241
+ describe = describeJsonValue;
4242
+ userToggled = /* @__PURE__ */ new Map;
4240
4243
  isCollapsed(path, depth) {
4241
- if (this.userToggled.has(path))
4242
- return this.collapsedPaths.has(path);
4243
- return depth >= this.expandDepth();
4244
+ return this.userToggled.get(path) ?? depth >= this.expandDepth();
4244
4245
  }
4245
4246
  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);
4247
+ this.userToggled.set(path, !this.isCollapsed(path, depth));
4255
4248
  }
4256
4249
  static ɵfac = i0.ɵɵngDeclareFactory({
4257
4250
  minVersion: "12.0.0",
@@ -4857,10 +4850,7 @@ i0.ɵɵngDeclareClassMetadata({
4857
4850
  type: MarkedPipe,
4858
4851
  decorators: [{
4859
4852
  type: Pipe,
4860
- args: [{
4861
- name: "marked",
4862
- standalone: true
4863
- }]
4853
+ args: [{ name: "marked" }]
4864
4854
  }]
4865
4855
  });
4866
4856
  var AttachmentImageComponent = class AttachmentImageComponent2 {
@@ -5020,11 +5010,6 @@ i0.ɵɵngDeclareClassMetadata({
5020
5010
  }]
5021
5011
  }
5022
5012
  });
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
5013
  var MediaBlockHeadComponent = class MediaBlockHeadComponent2 {
5029
5014
  language = input.required(...ngDevMode ? [{ debugName: "language" }] : []);
5030
5015
  source = input.required(...ngDevMode ? [{ debugName: "source" }] : []);
@@ -5034,7 +5019,7 @@ var MediaBlockHeadComponent = class MediaBlockHeadComponent2 {
5034
5019
  sourceShown = input.required(...ngDevMode ? [{ debugName: "sourceShown" }] : []);
5035
5020
  canToggleSource = input.required(...ngDevMode ? [{ debugName: "canToggleSource" }] : []);
5036
5021
  toggleSource = output();
5037
- pendingLabel = computed(() => PENDING_LABEL[this.language()] ?? "translate_media_pending", ...ngDevMode ? [{ debugName: "pendingLabel" }] : []);
5022
+ pendingLabel = computed(() => mediaPendingLabel(this.language()), ...ngDevMode ? [{ debugName: "pendingLabel" }] : []);
5038
5023
  static ɵfac = i0.ɵɵngDeclareFactory({
5039
5024
  minVersion: "12.0.0",
5040
5025
  version: "22.2.0",
@@ -5509,6 +5494,9 @@ var MessageTextPartComponent = class MessageTextPartComponent2 {
5509
5494
  streaming = input(false, ...ngDevMode ? [{ debugName: "streaming" }] : []);
5510
5495
  debugMode = input(false, ...ngDevMode ? [{ debugName: "debugMode" }] : []);
5511
5496
  attachments = input([], ...ngDevMode ? [{ debugName: "attachments" }] : []);
5497
+ config = inject(CORTEX_CONFIG);
5498
+ smoother = null;
5499
+ isFirstRender = true;
5512
5500
  displayedText = signal("", ...ngDevMode ? [{ debugName: "displayedText" }] : []);
5513
5501
  fading = signal([], ...ngDevMode ? [{ debugName: "fading" }] : []);
5514
5502
  segments = computed(() => this.role() === "assistant" ? segmentMessageText(this.displayedText(), mediaLanguages(this.config().mediaRenderers)) : [{
@@ -5519,9 +5507,6 @@ var MessageTextPartComponent = class MessageTextPartComponent2 {
5519
5507
  attachmentFor(id) {
5520
5508
  return this.attachments().find((attachment) => attachment.id.toLowerCase() === id);
5521
5509
  }
5522
- config = inject(CORTEX_CONFIG);
5523
- smoother = null;
5524
- isFirstRender = true;
5525
5510
  constructor() {
5526
5511
  effect(() => {
5527
5512
  const part = this.textPart();
@@ -5533,31 +5518,28 @@ var MessageTextPartComponent = class MessageTextPartComponent2 {
5533
5518
  this.isFirstRender = false;
5534
5519
  return;
5535
5520
  }
5521
+ const smoother = this.ensureSmoother();
5536
5522
  if (this.isFirstRender) {
5537
- this.ensureSmoother();
5538
- this.smoother.seed(part.content);
5539
5523
  this.isFirstRender = false;
5524
+ smoother.seed(part.content);
5540
5525
  return;
5541
5526
  }
5542
- this.isFirstRender = false;
5543
- this.ensureSmoother();
5544
- this.smoother.update(part.content, false);
5527
+ smoother.update(part.content, false);
5545
5528
  });
5546
5529
  }
5547
5530
  ngOnDestroy() {
5548
5531
  this.destroySmoother();
5549
5532
  }
5550
5533
  destroySmoother() {
5551
- if (this.smoother) {
5552
- this.smoother.destroy();
5553
- this.smoother = null;
5554
- }
5534
+ this.smoother?.destroy();
5535
+ this.smoother = null;
5555
5536
  }
5556
5537
  ensureSmoother() {
5557
- if (this.smoother)
5558
- return;
5559
- this.smoother = new StreamTextSmoother((text, fading) => this.show(text, fading));
5560
- this.smoother.seed(this.displayedText());
5538
+ if (!this.smoother) {
5539
+ this.smoother = new StreamTextSmoother((text, fading) => this.show(text, fading));
5540
+ this.smoother.seed(this.displayedText());
5541
+ }
5542
+ return this.smoother;
5561
5543
  }
5562
5544
  show(text, fading) {
5563
5545
  this.displayedText.set(text);
@@ -6012,10 +5994,7 @@ i0.ɵɵngDeclareClassMetadata({
6012
5994
  type: HighlightPipe,
6013
5995
  decorators: [{
6014
5996
  type: Pipe,
6015
- args: [{
6016
- name: "highlight",
6017
- standalone: true
6018
- }]
5997
+ args: [{ name: "highlight" }]
6019
5998
  }]
6020
5999
  });
6021
6000
  var MessageToolCallOutcomeComponent = class MessageToolCallOutcomeComponent2 {
@@ -6962,33 +6941,7 @@ var LocationPickerComponent = class LocationPickerComponent2 {
6962
6941
  center = input.required(...ngDevMode ? [{ debugName: "center" }] : []);
6963
6942
  submit = input.required(...ngDevMode ? [{ debugName: "submit" }] : []);
6964
6943
  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" }] : []);
6944
+ hint = computed(() => locationPickerHint(this.picked()), ...ngDevMode ? [{ debugName: "hint" }] : []);
6992
6945
  describe = describeLocation;
6993
6946
  host = viewChild.required("host", ...ngDevMode ? [{ debugName: "host" }] : []);
6994
6947
  picker;
@@ -7446,12 +7399,13 @@ i0.ɵɵngDeclareClassMetadata({
7446
7399
  }]
7447
7400
  }
7448
7401
  });
7449
- var BUILT_IN_TOOL_COMPONENTS = { [REQUEST_LOCATION_TOOL]: LocationInputComponent };
7402
+ var BUILT_IN_TOOL_COMPONENTS = /* @__PURE__ */ new Map([[REQUEST_LOCATION_TOOL, LocationInputComponent]]);
7450
7403
  var MessageToolCallAnimatedComponent = class MessageToolCallAnimatedComponent2 {
7451
7404
  message = input.required(...ngDevMode ? [{ debugName: "message" }] : []);
7452
7405
  toolCallPart = input.required(...ngDevMode ? [{ debugName: "toolCallPart" }] : []);
7453
7406
  config = inject(CORTEX_CONFIG);
7454
7407
  locale = inject(CORTEX_LOCALE);
7408
+ chatService = inject(CortexChatService);
7455
7409
  mountedComponent = computed(() => {
7456
7410
  const part = this.toolCallPart();
7457
7411
  const setOutput = (output2) => this.chatService.addToolResult(part.id, part.name, output2);
@@ -7465,7 +7419,7 @@ var MessageToolCallAnimatedComponent = class MessageToolCallAnimatedComponent2 {
7465
7419
  setOutput
7466
7420
  }
7467
7421
  };
7468
- const builtIn2 = this.owed() || isSettledToolState(part.state) ? BUILT_IN_TOOL_COMPONENTS[part.name] : undefined;
7422
+ const builtIn2 = this.owed() || isSettledToolState(part.state) ? BUILT_IN_TOOL_COMPONENTS.get(part.name) : undefined;
7469
7423
  return builtIn2 ? {
7470
7424
  type: builtIn2,
7471
7425
  inputs: {
@@ -7480,9 +7434,7 @@ var MessageToolCallAnimatedComponent = class MessageToolCallAnimatedComponent2 {
7480
7434
  approvalRequested = computed(() => this.toolCallPart().state === "approval-requested" && !this.chatService.isAgentWorking(), ...ngDevMode ? [{ debugName: "approvalRequested" }] : []);
7481
7435
  prompt = computed(() => approvalPrompt(this.toolCallPart(), this.locale()) ?? translate(this.locale(), "translate_approval_prompt"), ...ngDevMode ? [{ debugName: "prompt" }] : []);
7482
7436
  respond(approved) {
7483
- const part = this.toolCallPart();
7484
- const approvalId = part.approval?.id ?? `approval_${part.id}`;
7485
- this.chatService.respondToApproval(approvalId, approved);
7437
+ this.chatService.respondToApproval(approvalIdOf(this.toolCallPart()), approved);
7486
7438
  }
7487
7439
  animation = computed(() => toolCallAnimation(this.toolCallPart()), ...ngDevMode ? [{ debugName: "animation" }] : []);
7488
7440
  animState = computed(() => this.animation().state, ...ngDevMode ? [{ debugName: "animState" }] : []);
@@ -7494,7 +7446,6 @@ var MessageToolCallAnimatedComponent = class MessageToolCallAnimatedComponent2 {
7494
7446
  const count2 = this.animation().rowCount;
7495
7447
  return count2 === undefined ? undefined : translate(this.locale(), "translate_rows_read", { count: count2 });
7496
7448
  }, ...ngDevMode ? [{ debugName: "rowsLabel" }] : []);
7497
- chatService = inject(CortexChatService);
7498
7449
  static ɵfac = i0.ɵɵngDeclareFactory({
7499
7450
  minVersion: "12.0.0",
7500
7451
  version: "22.2.0",
@@ -8512,7 +8463,7 @@ var MessageBodyComponent = class MessageBodyComponent2 {
8512
8463
  const mark = this.fold()?.get(part);
8513
8464
  if (mark?.kind !== "more")
8514
8465
  return;
8515
- const key = mark.count === 1 ? "translate_one_more_step" : "translate_n_more_steps";
8466
+ const key = pluralKey(mark.count, "translate_one_more_step", "translate_n_more_steps");
8516
8467
  return {
8517
8468
  runId: mark.runId,
8518
8469
  count: mark.count,
@@ -9456,7 +9407,7 @@ var ThreadListComponent = class ThreadListComponent2 {
9456
9407
  this.chatService.deleteThread(threadId).subscribe();
9457
9408
  }
9458
9409
  countKey(count2) {
9459
- return count2 === 1 ? "translate_one_conversation" : "translate_n_conversations";
9410
+ return pluralKey(count2, "translate_one_conversation", "translate_n_conversations");
9460
9411
  }
9461
9412
  relativeTime(iso) {
9462
9413
  return timeLabel(iso, this.locale());
@@ -9484,7 +9435,6 @@ var ThreadListComponent = class ThreadListComponent2 {
9484
9435
  template: `@let threads = threadService.threads();
9485
9436
  @let threadCount = threads?.length ?? 0;
9486
9437
 
9487
- <!-- Threads header -->
9488
9438
  <div class="cortex-widget__threads-header">
9489
9439
  <!-- Back to chat (helper mode; full mode hides it, the sidebar is always visible) -->
9490
9440
  <button
@@ -9527,10 +9477,9 @@ var ThreadListComponent = class ThreadListComponent2 {
9527
9477
  </button>
9528
9478
  </div>
9529
9479
 
9530
- <!-- Threads list -->
9531
9480
  <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. -->
9481
+ <!-- The loading, listed and empty states are siblings rather than an if/else
9482
+ ladder, so the row markup sits one level shallower. -->
9534
9483
  @if (threads === undefined) {
9535
9484
  @for (i of [1, 2, 3, 4]; track i) {
9536
9485
  <div class="cortex-widget__thread-skeleton">
@@ -9552,7 +9501,6 @@ var ThreadListComponent = class ThreadListComponent2 {
9552
9501
  class="cortex-widget__thread-item"
9553
9502
  [class.cortex-widget__thread-item--active]="isActive"
9554
9503
  >
9555
- <!-- Thread icon -->
9556
9504
  <div class="cortex-widget__thread-icon" [class.cortex-widget__thread-icon--active]="isActive">
9557
9505
  <svg width="14" height="14" viewBox="0 0 16 16" fill="none">
9558
9506
  <!-- Rounded speech bubble with a tail, on the shared 16x16 icon grid. -->
@@ -9566,7 +9514,6 @@ var ThreadListComponent = class ThreadListComponent2 {
9566
9514
  </svg>
9567
9515
  </div>
9568
9516
 
9569
- <!-- Thread info -->
9570
9517
  <div class="cortex-widget__thread-info">
9571
9518
  <div class="cortex-widget__thread-title-row">
9572
9519
  <p
@@ -9593,7 +9540,6 @@ var ThreadListComponent = class ThreadListComponent2 {
9593
9540
  }
9594
9541
  </div>
9595
9542
 
9596
- <!-- Delete button -->
9597
9543
  <button
9598
9544
  (click)="deleteThread($event, thread.id)"
9599
9545
  class="cortex-widget__thread-delete"
@@ -9609,7 +9555,6 @@ var ThreadListComponent = class ThreadListComponent2 {
9609
9555
  </svg>
9610
9556
  </button>
9611
9557
 
9612
- <!-- Arrow -->
9613
9558
  <svg
9614
9559
  class="cortex-widget__thread-arrow"
9615
9560
  [class.cortex-widget__thread-arrow--active]="isActive"
@@ -9688,7 +9633,6 @@ i0.ɵɵngDeclareClassMetadata({
9688
9633
  template: `@let threads = threadService.threads();
9689
9634
  @let threadCount = threads?.length ?? 0;
9690
9635
 
9691
- <!-- Threads header -->
9692
9636
  <div class="cortex-widget__threads-header">
9693
9637
  <!-- Back to chat (helper mode; full mode hides it, the sidebar is always visible) -->
9694
9638
  <button
@@ -9731,10 +9675,9 @@ i0.ɵɵngDeclareClassMetadata({
9731
9675
  </button>
9732
9676
  </div>
9733
9677
 
9734
- <!-- Threads list -->
9735
9678
  <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. -->
9679
+ <!-- The loading, listed and empty states are siblings rather than an if/else
9680
+ ladder, so the row markup sits one level shallower. -->
9738
9681
  @if (threads === undefined) {
9739
9682
  @for (i of [1, 2, 3, 4]; track i) {
9740
9683
  <div class="cortex-widget__thread-skeleton">
@@ -9756,7 +9699,6 @@ i0.ɵɵngDeclareClassMetadata({
9756
9699
  class="cortex-widget__thread-item"
9757
9700
  [class.cortex-widget__thread-item--active]="isActive"
9758
9701
  >
9759
- <!-- Thread icon -->
9760
9702
  <div class="cortex-widget__thread-icon" [class.cortex-widget__thread-icon--active]="isActive">
9761
9703
  <svg width="14" height="14" viewBox="0 0 16 16" fill="none">
9762
9704
  <!-- Rounded speech bubble with a tail, on the shared 16x16 icon grid. -->
@@ -9770,7 +9712,6 @@ i0.ɵɵngDeclareClassMetadata({
9770
9712
  </svg>
9771
9713
  </div>
9772
9714
 
9773
- <!-- Thread info -->
9774
9715
  <div class="cortex-widget__thread-info">
9775
9716
  <div class="cortex-widget__thread-title-row">
9776
9717
  <p
@@ -9797,7 +9738,6 @@ i0.ɵɵngDeclareClassMetadata({
9797
9738
  }
9798
9739
  </div>
9799
9740
 
9800
- <!-- Delete button -->
9801
9741
  <button
9802
9742
  (click)="deleteThread($event, thread.id)"
9803
9743
  class="cortex-widget__thread-delete"
@@ -9813,7 +9753,6 @@ i0.ɵɵngDeclareClassMetadata({
9813
9753
  </svg>
9814
9754
  </button>
9815
9755
 
9816
- <!-- Arrow -->
9817
9756
  <svg
9818
9757
  class="cortex-widget__thread-arrow"
9819
9758
  [class.cortex-widget__thread-arrow--active]="isActive"
@@ -10003,7 +9942,6 @@ var CortexChatWidgetComponent = class CortexChatWidgetComponent2 {
10003
9942
  (dragover)="onWidgetDragOver($event)"
10004
9943
  (drop)="onWidgetDrop($event)"
10005
9944
  >
10006
- <!-- SCREEN 1: THREADS -->
10007
9945
  <cortex-thread-list
10008
9946
  class="cortex-widget__screen"
10009
9947
  [class.cortex-widget__screen--active]="screen() === 'threads'"
@@ -10013,7 +9951,6 @@ var CortexChatWidgetComponent = class CortexChatWidgetComponent2 {
10013
9951
  (backRequested)="closeHistory()"
10014
9952
  />
10015
9953
 
10016
- <!-- SCREEN 2: CHAT -->
10017
9954
  <div
10018
9955
  class="cortex-widget__screen"
10019
9956
  [class.cortex-widget__screen--active]="screen() === 'chat'"
@@ -10033,11 +9970,9 @@ var CortexChatWidgetComponent = class CortexChatWidgetComponent2 {
10033
9970
  } @else if (chatService.isLoadingMessages() && !chatService.isAgentWorking()) {
10034
9971
  <cortex-messages-skeleton />
10035
9972
  } @else {
10036
- <!-- Messages area -->
10037
9973
  <cortex-message-list class="cortex-widget__messages" [debugMode]="debugMode()" />
10038
9974
  }
10039
9975
 
10040
- <!-- Agent working indicator -->
10041
9976
  @if (chatService.isAgentWorking() && !chatService.hasPendingToolCalls()) {
10042
9977
  <div class="cortex-widget__working">
10043
9978
  <div class="cortex-widget__working-dots">
@@ -10166,7 +10101,6 @@ i0.ɵɵngDeclareClassMetadata({
10166
10101
  (dragover)="onWidgetDragOver($event)"
10167
10102
  (drop)="onWidgetDrop($event)"
10168
10103
  >
10169
- <!-- SCREEN 1: THREADS -->
10170
10104
  <cortex-thread-list
10171
10105
  class="cortex-widget__screen"
10172
10106
  [class.cortex-widget__screen--active]="screen() === 'threads'"
@@ -10176,7 +10110,6 @@ i0.ɵɵngDeclareClassMetadata({
10176
10110
  (backRequested)="closeHistory()"
10177
10111
  />
10178
10112
 
10179
- <!-- SCREEN 2: CHAT -->
10180
10113
  <div
10181
10114
  class="cortex-widget__screen"
10182
10115
  [class.cortex-widget__screen--active]="screen() === 'chat'"
@@ -10196,11 +10129,9 @@ i0.ɵɵngDeclareClassMetadata({
10196
10129
  } @else if (chatService.isLoadingMessages() && !chatService.isAgentWorking()) {
10197
10130
  <cortex-messages-skeleton />
10198
10131
  } @else {
10199
- <!-- Messages area -->
10200
10132
  <cortex-message-list class="cortex-widget__messages" [debugMode]="debugMode()" />
10201
10133
  }
10202
10134
 
10203
- <!-- Agent working indicator -->
10204
10135
  @if (chatService.isAgentWorking() && !chatService.hasPendingToolCalls()) {
10205
10136
  <div class="cortex-widget__working">
10206
10137
  <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.0",
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>;