@things-factory/ai-assistant 10.1.24 → 10.1.26

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.
Files changed (48) hide show
  1. package/client/components/assistant-chat.ts +90 -18
  2. package/client/components/assistant-mode.test.ts +97 -0
  3. package/client/components/assistant-mode.ts +130 -0
  4. package/client/index.ts +1 -1
  5. package/dist-client/components/assistant-chat.d.ts +15 -4
  6. package/dist-client/components/assistant-chat.js +73 -18
  7. package/dist-client/components/assistant-chat.js.map +1 -1
  8. package/dist-client/components/assistant-mode.d.ts +97 -0
  9. package/dist-client/components/assistant-mode.js +36 -0
  10. package/dist-client/components/assistant-mode.js.map +1 -0
  11. package/dist-client/components/assistant-mode.test.d.ts +1 -0
  12. package/dist-client/components/assistant-mode.test.js +85 -0
  13. package/dist-client/components/assistant-mode.test.js.map +1 -0
  14. package/dist-client/index.d.ts +1 -1
  15. package/dist-client/index.js +1 -1
  16. package/dist-client/index.js.map +1 -1
  17. package/dist-client/tsconfig.tsbuildinfo +1 -1
  18. package/dist-server/index.d.ts +1 -0
  19. package/dist-server/index.js +1 -0
  20. package/dist-server/index.js.map +1 -1
  21. package/dist-server/service/assistant-chat-resolver.js +3 -1
  22. package/dist-server/service/assistant-chat-resolver.js.map +1 -1
  23. package/dist-server/service/index.d.ts +1 -0
  24. package/dist-server/service/index.js +1 -0
  25. package/dist-server/service/index.js.map +1 -1
  26. package/dist-server/service/tool-access.d.ts +4 -0
  27. package/dist-server/service/tool-access.js +23 -0
  28. package/dist-server/service/tool-access.js.map +1 -0
  29. package/dist-server/tool-registry-boot-report.d.ts +3 -0
  30. package/dist-server/tool-registry-boot-report.js +29 -0
  31. package/dist-server/tool-registry-boot-report.js.map +1 -0
  32. package/dist-server/tsconfig.tsbuildinfo +1 -1
  33. package/docs/session-controller.md +1 -1
  34. package/package.json +5 -5
  35. package/server/index.ts +1 -0
  36. package/server/service/assistant-chat-resolver.ts +3 -1
  37. package/server/service/index.ts +1 -0
  38. package/server/service/tool-access.test.ts +48 -0
  39. package/server/service/tool-access.ts +27 -0
  40. package/server/tool-registry-boot-report.test.ts +18 -0
  41. package/server/tool-registry-boot-report.ts +26 -0
  42. package/test/assistant-request-context.test.ts +2 -2
  43. package/test/assistant-session-controller.test.ts +0 -1
  44. package/test/assistant-session-toolbar.test.ts +2 -2
  45. package/client/utils/board-edit-patch.ts +0 -374
  46. package/dist-client/utils/board-edit-patch.d.ts +0 -157
  47. package/dist-client/utils/board-edit-patch.js +0 -284
  48. package/dist-client/utils/board-edit-patch.js.map +0 -1
@@ -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,25 @@ 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 host that declares a mode gets the mode and nothing else — a field it leaves out is empty,
444
+ * never filled from these properties or the registered defaults. A host that has not declared
445
+ * one keeps the separate properties and the global defaults it had before.
446
+ */
447
+ get conversation() {
448
+ return resolveConversation(this.mode, {
449
+ systemPrompt: this.systemPrompt,
450
+ toolCategories: this.toolCategories,
451
+ hostContext: this.hostContext,
452
+ chatEndpoint: this.chatEndpoint
453
+ }, chatDefaults);
454
+ }
455
+ rebuildMentionCaches() {
456
+ this.cachedCatalogCandidates = buildCatalogCandidates(this.conversation.catalogEntries);
457
+ this.cachedSlashCandidates = buildSlashCandidates(this.conversation.slashTemplates);
458
+ }
435
459
  static { this.styles = [
436
460
  // 어플리케이션 표준 스크롤바 (--scrollbar-width / --scrollbar-thumb-color 등 호스트 변수 따름)
437
461
  ScrollbarStyles,
@@ -1938,6 +1962,33 @@ let OxAssistantChat = class OxAssistantChat extends LitElement {
1938
1962
  this.input = this.autoAsk;
1939
1963
  this.send();
1940
1964
  }
1965
+ /*
1966
+ * The subject changed, so the conversation is over.
1967
+ *
1968
+ * A conversation about station 3 is not a conversation about station 7. Leaving the old one
1969
+ * on screen means the user reads an answer about a screen they are no longer looking at,
1970
+ * and every host that met this wrote its own guard: plant re-checked the context on each
1971
+ * send and threw when it had moved, twin closed its session when the anchor changed. The
1972
+ * mode carries an id, so the component can do it once, here.
1973
+ *
1974
+ * The host still owns `sessionId`; it hears `assistant-mode-changed` and decides whether
1975
+ * this subject gets a stored session of its own.
1976
+ */
1977
+ if (changed.has('mode') && isDifferentConversation(changed.get('mode'), this.mode)) {
1978
+ this.rebuildMentionCaches();
1979
+ this.lines = [];
1980
+ this.pickedMentions.clear();
1981
+ this.pickedUserMentions.clear();
1982
+ this.cachedUserCandidates = [];
1983
+ this.errorMessage = undefined;
1984
+ this.input = '';
1985
+ this._seenMessageIds.clear();
1986
+ this.dispatchEvent(new CustomEvent('assistant-mode-changed', {
1987
+ detail: { mode: this.mode },
1988
+ bubbles: true,
1989
+ composed: true
1990
+ }));
1991
+ }
1941
1992
  if (changed.has('sessionId') && this.adoptingSession) {
1942
1993
  this.adoptingSession = false;
1943
1994
  this._startPresence();
@@ -2530,7 +2581,7 @@ let OxAssistantChat = class OxAssistantChat extends LitElement {
2530
2581
  }
2531
2582
  }
2532
2583
  dispatchActions(actions) {
2533
- this.dispatchEvent(new CustomEvent('board-action-execute', {
2584
+ this.dispatchEvent(new CustomEvent('scene-action-execute', {
2534
2585
  detail: { actions, sessionId: this.sessionId },
2535
2586
  bubbles: true,
2536
2587
  composed: true
@@ -2616,7 +2667,7 @@ let OxAssistantChat = class OxAssistantChat extends LitElement {
2616
2667
  return availableTriggers({
2617
2668
  hasMentionableThings: !!(this.boardProvider || this.currentBoard || this.knownTypes?.length),
2618
2669
  hasSession: !!this.sessionId,
2619
- slashTemplateCount: chatDefaults.slashTemplates.length
2670
+ slashTemplateCount: this.conversation.slashTemplates.length
2620
2671
  });
2621
2672
  }
2622
2673
  static { this.EXAMPLE_GROUPS = [
@@ -2729,8 +2780,8 @@ let OxAssistantChat = class OxAssistantChat extends LitElement {
2729
2780
  <span class="badge">${i18next.t('ai-assistant.label.korean-supported')}</span>
2730
2781
  <span class="badge">${i18next.t('ai-assistant.label.multi-command')}</span>
2731
2782
  <span class="badge">${i18next.t('ai-assistant.label.review-able')}</span>
2732
- ${chatDefaults.footerNoticeKey
2733
- ? html `<br />${i18next.t(chatDefaults.footerNoticeKey)}`
2783
+ ${this.conversation.footerNoticeKey
2784
+ ? html `<br />${i18next.t(this.conversation.footerNoticeKey)}`
2734
2785
  : ''}
2735
2786
  </div>
2736
2787
  </div>
@@ -2872,7 +2923,7 @@ let OxAssistantChat = class OxAssistantChat extends LitElement {
2872
2923
  to live here named a 3D modeller's operations in hardcoded Korean, and it reached the
2873
2924
  plant and twin chats too.
2874
2925
  */
2875
- const rawChoices = Array.isArray(p.choices) ? p.choices : (chatDefaults.proposalChoices ?? []);
2926
+ const rawChoices = Array.isArray(p.choices) ? p.choices : this.conversation.proposalChoices;
2876
2927
  return html `
2877
2928
  <div class="proposal ${sent ? 'sent' : ''}">
2878
2929
  <md-icon>${p.icon || (p.source ? 'view_in_ar' : 'bolt')}</md-icon>
@@ -2900,10 +2951,10 @@ let OxAssistantChat = class OxAssistantChat extends LitElement {
2900
2951
  This badge used to read "there are chips" as "the model is in the 3D viewer" and
2901
2952
  say so, in a component that plant and twin also use.
2902
2953
  */''}
2903
- ${this.stagedProposals.has(key) && chatDefaults.stagedNoticeKey ? html `
2954
+ ${this.stagedProposals.has(key) && this.conversation.stagedNoticeKey ? html `
2904
2955
  <span class="staged-badge">
2905
2956
  <md-icon>check_circle</md-icon>
2906
- <span>${i18next.t(chatDefaults.stagedNoticeKey)}</span>
2957
+ <span>${i18next.t(this.conversation.stagedNoticeKey)}</span>
2907
2958
  </span>
2908
2959
  ` : nothing}
2909
2960
  </div>
@@ -3274,7 +3325,7 @@ let OxAssistantChat = class OxAssistantChat extends LitElement {
3274
3325
  let requestBase;
3275
3326
  try {
3276
3327
  const provided = this.contextProvider?.() || {};
3277
- requestContext = structuredClone({ systemPrompt: this.systemPrompt, hostContext: this.hostContext, ...provided });
3328
+ requestContext = structuredClone({ systemPrompt: this.conversation.systemPrompt, hostContext: this.conversation.hostContext, ...provided });
3278
3329
  liveBoard = structuredClone(this.boardProvider ? this.boardProvider() : this.currentBoard);
3279
3330
  requestBase = { version: 1, sessionId: this.sessionId, hostContext: requestContext.hostContext,
3280
3331
  modelFingerprint: assistantModelFingerprint(liveBoard) };
@@ -3348,7 +3399,7 @@ let OxAssistantChat = class OxAssistantChat extends LitElement {
3348
3399
  // 라이브 보드 우선 — 호스트의 캔버스가 사용자 수작업 편집을 들고 있을 수 있음.
3349
3400
  // boardProvider 가 있으면 send 시점에 그것을 pull, 없으면 정적 currentBoard.
3350
3401
  // mentions 는 위에서 이미 계산해 user line 에 thread — 그대로 mutation 입력으로 재사용.
3351
- const neutral = this.chatEndpoint === 'assistantChat';
3402
+ const neutral = this.conversation.chatEndpoint === 'assistantChat';
3352
3403
  const result = await client.mutate({
3353
3404
  mutation: neutral ? ASSISTANT_CHAT_MUTATION : BOARD_AI_CHAT_MUTATION,
3354
3405
  variables: {
@@ -3359,7 +3410,7 @@ let OxAssistantChat = class OxAssistantChat extends LitElement {
3359
3410
  systemPrompt: requestContext.systemPrompt,
3360
3411
  truncateAfterMessageId: this._truncateAfterId,
3361
3412
  hostContext: requestContext.hostContext,
3362
- toolCategories: this.toolCategories,
3413
+ toolCategories: this.conversation.toolCategories,
3363
3414
  requireGroundingTools: this.requireGroundingTools
3364
3415
  })
3365
3416
  : buildChatMutationInput({
@@ -3369,7 +3420,7 @@ let OxAssistantChat = class OxAssistantChat extends LitElement {
3369
3420
  scopes: this.scopes,
3370
3421
  truncateAfterMessageId: this._truncateAfterId,
3371
3422
  hostContext: requestContext.hostContext,
3372
- toolCategories: this.toolCategories,
3423
+ toolCategories: this.conversation.toolCategories,
3373
3424
  boardTools: this.boardTools,
3374
3425
  requireGroundingTools: this.requireGroundingTools,
3375
3426
  knownTypes: this.knownTypes,
@@ -3416,7 +3467,7 @@ let OxAssistantChat = class OxAssistantChat extends LitElement {
3416
3467
  }
3417
3468
  // 호스트로 patch 이벤트 전파
3418
3469
  if (out.patch) {
3419
- this.dispatchEvent(new CustomEvent('board-edit-patch', {
3470
+ this.dispatchEvent(new CustomEvent('scene-edit-patch', {
3420
3471
  detail: {
3421
3472
  patch: out.patch,
3422
3473
  requestBase,
@@ -3431,7 +3482,7 @@ let OxAssistantChat = class OxAssistantChat extends LitElement {
3431
3482
  }
3432
3483
  // 호스트로 ephemeral scene 조작 actions 전파 (selection / view / mode)
3433
3484
  if (Array.isArray(out.actions) && out.actions.length > 0) {
3434
- this.dispatchEvent(new CustomEvent('board-action-execute', {
3485
+ this.dispatchEvent(new CustomEvent('scene-action-execute', {
3435
3486
  detail: { actions: out.actions, sessionId: out.sessionId, requestBase },
3436
3487
  bubbles: true,
3437
3488
  composed: true
@@ -3504,6 +3555,10 @@ __decorate([
3504
3555
  property({ type: String, attribute: 'chat-endpoint' }),
3505
3556
  __metadata("design:type", String)
3506
3557
  ], OxAssistantChat.prototype, "chatEndpoint", void 0);
3558
+ __decorate([
3559
+ property({ attribute: false }),
3560
+ __metadata("design:type", Object)
3561
+ ], OxAssistantChat.prototype, "mode", void 0);
3507
3562
  __decorate([
3508
3563
  property({ type: String, attribute: 'system-prompt' }),
3509
3564
  __metadata("design:type", String)