@things-factory/ai-assistant 10.1.20 → 10.1.25

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.
@@ -9,8 +9,8 @@ import { __decorate, __metadata } from "tslib";
9
9
  * - scopes / knownTypes / categories: 도메인 컨텍스트
10
10
  *
11
11
  * 출력 (이벤트):
12
- * - `board-edit-patch` { detail: { patch, summary, confidence, patchId } }
13
- * 호스트가 받아서 보드 모델에 적용 (applyBoardEditPatch helper).
12
+ * - `scene-edit-patch` { detail: { patch, summary, confidence, patchId } }
13
+ * 호스트가 받아서 보드 모델에 적용 (applyScenePatch from @operato/scene-ops).
14
14
  * - `chat-followup` { detail: { question } }
15
15
  *
16
16
  * 모드 전환은 컨테이너 (워크스페이스) 의 책임. 이 컴포넌트는 자체로 풀 채팅 UX.
@@ -43,6 +43,7 @@ import { buildMentionCandidates, buildCatalogCandidates, buildSlashCandidates, b
43
43
  * 뜨지 않는 것이 맞다.
44
44
  */
45
45
  import { chatDefaults } from './chat-defaults.js';
46
+ import { isDifferentConversation, resolveConversation } from './assistant-mode.js';
46
47
  import { availableTriggers } from './chat-triggers.js';
47
48
  function formatFileSize(bytes) {
48
49
  if (!bytes || bytes < 1024)
@@ -259,9 +260,13 @@ let OxAssistantChat = class OxAssistantChat extends LitElement {
259
260
  * textarea 에는 @username 만 보이지만 server 한테는 정확한 userId 전달.
260
261
  * send 시 mutation input.userMentions 로 함께 전송. */
261
262
  this.pickedUserMentions = new Map();
262
- /** Default 카탈로그 후보 캐시 — chat panel mount 시 1회 빌드 */
263
+ /*
264
+ * The `@` and `/` candidates, built once per mode.
265
+ *
266
+ * These were built at field initialisation, which meant a host could not change what the
267
+ * panel offers without replacing the element. A mode change rebuilds them below.
268
+ */
263
269
  this.cachedCatalogCandidates = buildCatalogCandidates(chatDefaults.catalogEntries);
264
- /** Default slash template 후보 캐시 — chat panel mount 시 1회 빌드 */
265
270
  this.cachedSlashCandidates = buildSlashCandidates(chatDefaults.slashTemplates);
266
271
  /** `@` 마지막 query 의 도메인 사용자 후보 캐시 — userProvider 응답 도착 시 갱신.
267
272
  * query 별 캐시가 아니라 단순 "최근 결과" — async race 회피. */
@@ -417,7 +422,7 @@ let OxAssistantChat = class OxAssistantChat extends LitElement {
417
422
  The screen still shows nothing either way. There is no sentence to show, and inventing one is
418
423
  what this whole correction removed.
419
424
  */
420
- if (!chatDefaults.stagedNoticeKey && !OxAssistantChat_1.warnedMissingStagedNotice) {
425
+ if (!this.conversation.stagedNoticeKey && !OxAssistantChat_1.warnedMissingStagedNotice) {
421
426
  OxAssistantChat_1.warnedMissingStagedNotice = true;
422
427
  console.warn('[assistant-chat] a host reported a proposal staged but registered no `stagedNoticeKey`, ' +
423
428
  'so the card can say nothing. Pass one to `registerChatDefaults` from the host.');
@@ -432,6 +437,24 @@ let OxAssistantChat = class OxAssistantChat extends LitElement {
432
437
  get _myEmail() {
433
438
  return auth.credential?.email;
434
439
  }
440
+ /*
441
+ * ── What this conversation is, resolved ──────────────────────────────────────────────
442
+ *
443
+ * A mode answers first. A host that has not declared one keeps the separate properties and
444
+ * the global defaults it had before, which is what every consumer written before modes does.
445
+ */
446
+ get conversation() {
447
+ return resolveConversation(this.mode, {
448
+ systemPrompt: this.systemPrompt,
449
+ toolCategories: this.toolCategories,
450
+ hostContext: this.hostContext,
451
+ chatEndpoint: this.chatEndpoint
452
+ }, chatDefaults);
453
+ }
454
+ rebuildMentionCaches() {
455
+ this.cachedCatalogCandidates = buildCatalogCandidates(this.conversation.catalogEntries);
456
+ this.cachedSlashCandidates = buildSlashCandidates(this.conversation.slashTemplates);
457
+ }
435
458
  static { this.styles = [
436
459
  // 어플리케이션 표준 스크롤바 (--scrollbar-width / --scrollbar-thumb-color 등 호스트 변수 따름)
437
460
  ScrollbarStyles,
@@ -1938,6 +1961,33 @@ let OxAssistantChat = class OxAssistantChat extends LitElement {
1938
1961
  this.input = this.autoAsk;
1939
1962
  this.send();
1940
1963
  }
1964
+ /*
1965
+ * The subject changed, so the conversation is over.
1966
+ *
1967
+ * A conversation about station 3 is not a conversation about station 7. Leaving the old one
1968
+ * on screen means the user reads an answer about a screen they are no longer looking at,
1969
+ * and every host that met this wrote its own guard: plant re-checked the context on each
1970
+ * send and threw when it had moved, twin closed its session when the anchor changed. The
1971
+ * mode carries an id, so the component can do it once, here.
1972
+ *
1973
+ * The host still owns `sessionId`; it hears `assistant-mode-changed` and decides whether
1974
+ * this subject gets a stored session of its own.
1975
+ */
1976
+ if (changed.has('mode') && isDifferentConversation(changed.get('mode'), this.mode)) {
1977
+ this.rebuildMentionCaches();
1978
+ this.lines = [];
1979
+ this.pickedMentions.clear();
1980
+ this.pickedUserMentions.clear();
1981
+ this.cachedUserCandidates = [];
1982
+ this.errorMessage = undefined;
1983
+ this.input = '';
1984
+ this._seenMessageIds.clear();
1985
+ this.dispatchEvent(new CustomEvent('assistant-mode-changed', {
1986
+ detail: { mode: this.mode },
1987
+ bubbles: true,
1988
+ composed: true
1989
+ }));
1990
+ }
1941
1991
  if (changed.has('sessionId') && this.adoptingSession) {
1942
1992
  this.adoptingSession = false;
1943
1993
  this._startPresence();
@@ -2530,7 +2580,7 @@ let OxAssistantChat = class OxAssistantChat extends LitElement {
2530
2580
  }
2531
2581
  }
2532
2582
  dispatchActions(actions) {
2533
- this.dispatchEvent(new CustomEvent('board-action-execute', {
2583
+ this.dispatchEvent(new CustomEvent('scene-action-execute', {
2534
2584
  detail: { actions, sessionId: this.sessionId },
2535
2585
  bubbles: true,
2536
2586
  composed: true
@@ -2616,7 +2666,7 @@ let OxAssistantChat = class OxAssistantChat extends LitElement {
2616
2666
  return availableTriggers({
2617
2667
  hasMentionableThings: !!(this.boardProvider || this.currentBoard || this.knownTypes?.length),
2618
2668
  hasSession: !!this.sessionId,
2619
- slashTemplateCount: chatDefaults.slashTemplates.length
2669
+ slashTemplateCount: this.conversation.slashTemplates.length
2620
2670
  });
2621
2671
  }
2622
2672
  static { this.EXAMPLE_GROUPS = [
@@ -2729,8 +2779,8 @@ let OxAssistantChat = class OxAssistantChat extends LitElement {
2729
2779
  <span class="badge">${i18next.t('ai-assistant.label.korean-supported')}</span>
2730
2780
  <span class="badge">${i18next.t('ai-assistant.label.multi-command')}</span>
2731
2781
  <span class="badge">${i18next.t('ai-assistant.label.review-able')}</span>
2732
- ${chatDefaults.footerNoticeKey
2733
- ? html `<br />${i18next.t(chatDefaults.footerNoticeKey)}`
2782
+ ${this.conversation.footerNoticeKey
2783
+ ? html `<br />${i18next.t(this.conversation.footerNoticeKey)}`
2734
2784
  : ''}
2735
2785
  </div>
2736
2786
  </div>
@@ -2872,7 +2922,7 @@ let OxAssistantChat = class OxAssistantChat extends LitElement {
2872
2922
  to live here named a 3D modeller's operations in hardcoded Korean, and it reached the
2873
2923
  plant and twin chats too.
2874
2924
  */
2875
- const rawChoices = Array.isArray(p.choices) ? p.choices : (chatDefaults.proposalChoices ?? []);
2925
+ const rawChoices = Array.isArray(p.choices) ? p.choices : this.conversation.proposalChoices;
2876
2926
  return html `
2877
2927
  <div class="proposal ${sent ? 'sent' : ''}">
2878
2928
  <md-icon>${p.icon || (p.source ? 'view_in_ar' : 'bolt')}</md-icon>
@@ -2900,10 +2950,10 @@ let OxAssistantChat = class OxAssistantChat extends LitElement {
2900
2950
  This badge used to read "there are chips" as "the model is in the 3D viewer" and
2901
2951
  say so, in a component that plant and twin also use.
2902
2952
  */''}
2903
- ${this.stagedProposals.has(key) && chatDefaults.stagedNoticeKey ? html `
2953
+ ${this.stagedProposals.has(key) && this.conversation.stagedNoticeKey ? html `
2904
2954
  <span class="staged-badge">
2905
2955
  <md-icon>check_circle</md-icon>
2906
- <span>${i18next.t(chatDefaults.stagedNoticeKey)}</span>
2956
+ <span>${i18next.t(this.conversation.stagedNoticeKey)}</span>
2907
2957
  </span>
2908
2958
  ` : nothing}
2909
2959
  </div>
@@ -3274,7 +3324,7 @@ let OxAssistantChat = class OxAssistantChat extends LitElement {
3274
3324
  let requestBase;
3275
3325
  try {
3276
3326
  const provided = this.contextProvider?.() || {};
3277
- requestContext = structuredClone({ systemPrompt: this.systemPrompt, hostContext: this.hostContext, ...provided });
3327
+ requestContext = structuredClone({ systemPrompt: this.conversation.systemPrompt, hostContext: this.conversation.hostContext, ...provided });
3278
3328
  liveBoard = structuredClone(this.boardProvider ? this.boardProvider() : this.currentBoard);
3279
3329
  requestBase = { version: 1, sessionId: this.sessionId, hostContext: requestContext.hostContext,
3280
3330
  modelFingerprint: assistantModelFingerprint(liveBoard) };
@@ -3348,7 +3398,7 @@ let OxAssistantChat = class OxAssistantChat extends LitElement {
3348
3398
  // 라이브 보드 우선 — 호스트의 캔버스가 사용자 수작업 편집을 들고 있을 수 있음.
3349
3399
  // boardProvider 가 있으면 send 시점에 그것을 pull, 없으면 정적 currentBoard.
3350
3400
  // mentions 는 위에서 이미 계산해 user line 에 thread — 그대로 mutation 입력으로 재사용.
3351
- const neutral = this.chatEndpoint === 'assistantChat';
3401
+ const neutral = this.conversation.chatEndpoint === 'assistantChat';
3352
3402
  const result = await client.mutate({
3353
3403
  mutation: neutral ? ASSISTANT_CHAT_MUTATION : BOARD_AI_CHAT_MUTATION,
3354
3404
  variables: {
@@ -3359,7 +3409,7 @@ let OxAssistantChat = class OxAssistantChat extends LitElement {
3359
3409
  systemPrompt: requestContext.systemPrompt,
3360
3410
  truncateAfterMessageId: this._truncateAfterId,
3361
3411
  hostContext: requestContext.hostContext,
3362
- toolCategories: this.toolCategories,
3412
+ toolCategories: this.conversation.toolCategories,
3363
3413
  requireGroundingTools: this.requireGroundingTools
3364
3414
  })
3365
3415
  : buildChatMutationInput({
@@ -3369,7 +3419,7 @@ let OxAssistantChat = class OxAssistantChat extends LitElement {
3369
3419
  scopes: this.scopes,
3370
3420
  truncateAfterMessageId: this._truncateAfterId,
3371
3421
  hostContext: requestContext.hostContext,
3372
- toolCategories: this.toolCategories,
3422
+ toolCategories: this.conversation.toolCategories,
3373
3423
  boardTools: this.boardTools,
3374
3424
  requireGroundingTools: this.requireGroundingTools,
3375
3425
  knownTypes: this.knownTypes,
@@ -3416,7 +3466,7 @@ let OxAssistantChat = class OxAssistantChat extends LitElement {
3416
3466
  }
3417
3467
  // 호스트로 patch 이벤트 전파
3418
3468
  if (out.patch) {
3419
- this.dispatchEvent(new CustomEvent('board-edit-patch', {
3469
+ this.dispatchEvent(new CustomEvent('scene-edit-patch', {
3420
3470
  detail: {
3421
3471
  patch: out.patch,
3422
3472
  requestBase,
@@ -3431,7 +3481,7 @@ let OxAssistantChat = class OxAssistantChat extends LitElement {
3431
3481
  }
3432
3482
  // 호스트로 ephemeral scene 조작 actions 전파 (selection / view / mode)
3433
3483
  if (Array.isArray(out.actions) && out.actions.length > 0) {
3434
- this.dispatchEvent(new CustomEvent('board-action-execute', {
3484
+ this.dispatchEvent(new CustomEvent('scene-action-execute', {
3435
3485
  detail: { actions: out.actions, sessionId: out.sessionId, requestBase },
3436
3486
  bubbles: true,
3437
3487
  composed: true
@@ -3504,6 +3554,10 @@ __decorate([
3504
3554
  property({ type: String, attribute: 'chat-endpoint' }),
3505
3555
  __metadata("design:type", String)
3506
3556
  ], OxAssistantChat.prototype, "chatEndpoint", void 0);
3557
+ __decorate([
3558
+ property({ attribute: false }),
3559
+ __metadata("design:type", Object)
3560
+ ], OxAssistantChat.prototype, "mode", void 0);
3507
3561
  __decorate([
3508
3562
  property({ type: String, attribute: 'system-prompt' }),
3509
3563
  __metadata("design:type", String)