@yushaw/sanqian-chat 0.2.13 → 0.2.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +33 -0
- package/dist/{chunk-S6HCEDWX.mjs → chunk-YBHGKM2H.mjs} +18 -0
- package/dist/core/index.d.mts +56 -1
- package/dist/core/index.d.ts +56 -1
- package/dist/core/index.js +35 -6
- package/dist/core/index.mjs +35 -6
- package/dist/main/index.d.mts +64 -1
- package/dist/main/index.d.ts +64 -1
- package/dist/main/index.js +138 -2
- package/dist/main/index.mjs +138 -2
- package/dist/preload/entry.js +18 -0
- package/dist/preload/entry.mjs +1 -1
- package/dist/preload/factories.d.mts +54 -1
- package/dist/preload/factories.d.ts +54 -1
- package/dist/preload/factories.js +18 -0
- package/dist/preload/factories.mjs +1 -1
- package/dist/preload/index.js +18 -0
- package/dist/preload/index.mjs +1 -1
- package/dist/renderer/index.d.mts +67 -1
- package/dist/renderer/index.d.ts +67 -1
- package/dist/renderer/index.js +502 -336
- package/dist/renderer/index.mjs +450 -284
- package/package.json +2 -2
- package/src/renderer/styles/chat.css +6 -3
- package/src/renderer/styles/coreCss.ts +6 -3
- package/src/renderer/styles/safe.css +6 -3
- package/src/renderer/styles/tailwind.css +4 -2
- package/src/renderer/styles/variables.css +4 -2
package/README.md
CHANGED
|
@@ -148,3 +148,36 @@ src/renderer/styles/
|
|
|
148
148
|
- `useChatPanel.ts:86`: toggleMode 依赖 mode,每次 mode 变化重建
|
|
149
149
|
- 可用 useRef 避免重建,但当前影响可忽略
|
|
150
150
|
- 文件:`src/renderer/hooks/useAttachState.ts`, `src/renderer/hooks/useChatPanel.ts`
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
## Changelog
|
|
154
|
+
|
|
155
|
+
### 2026-01-11
|
|
156
|
+
|
|
157
|
+
**Ask AI 焦点管理**
|
|
158
|
+
|
|
159
|
+
- `ChatPanel.focusInput()` 方法:完整的焦点管理,支持 floating 和 embedded 模式
|
|
160
|
+
- macOS: `app.focus({ steal: true })` 确保应用获得前台焦点
|
|
161
|
+
- `floatingWindow.focus()` / `webContents.focus()` 确保窗口和 BrowserView 获得焦点
|
|
162
|
+
- IPC 消息通知渲染进程聚焦输入框
|
|
163
|
+
- `ChatAdapter.onFocusInput` 接口:渲染进程监听焦点事件
|
|
164
|
+
- `SanqianChatAPI.onFocusInput` preload API
|
|
165
|
+
|
|
166
|
+
**Bug 修复**
|
|
167
|
+
|
|
168
|
+
- 修复 session resources 发送前被删除的问题(移除了发送时的 `removeSessionResource` 调用)
|
|
169
|
+
- 修复 `AttachedResourceTags` 深色模式样式(使用正确的 CSS 变量)
|
|
170
|
+
- 清理 chip 布局的多余 padding/margin
|
|
171
|
+
|
|
172
|
+
### 2026-01-10
|
|
173
|
+
|
|
174
|
+
**Session Resources 功能实现**
|
|
175
|
+
|
|
176
|
+
新增应用主动推送临时上下文的能力(Session Resources):
|
|
177
|
+
|
|
178
|
+
- `ChatAdapter` 接口新增 `getSessionResources`、`onSessionResourceEvent`、`removeSessionResource` 方法
|
|
179
|
+
- `useChat` hook 新增 `sessionResources` 状态和 `removeSessionResource` 回调
|
|
180
|
+
- `FloatingChat` / `CompactChat` 组件支持显示 session resources chips
|
|
181
|
+
- IPC adapter 实现 session resources 相关 API
|
|
182
|
+
|
|
183
|
+
详见设计文档:`docs/session-resources-design.md`
|
|
@@ -33,6 +33,24 @@ function createSanqianChatApi() {
|
|
|
33
33
|
};
|
|
34
34
|
ipcRenderer.on("sanqian-chat:localeChanged", handler);
|
|
35
35
|
return () => ipcRenderer.removeListener("sanqian-chat:localeChanged", handler);
|
|
36
|
+
},
|
|
37
|
+
// Session Resources
|
|
38
|
+
getSessionResources: () => {
|
|
39
|
+
return ipcRenderer.sendSync("sanqian-chat:getSessionResourcesSync");
|
|
40
|
+
},
|
|
41
|
+
onSessionResourceEvent: (callback) => {
|
|
42
|
+
const handler = (_, event) => {
|
|
43
|
+
callback(event);
|
|
44
|
+
};
|
|
45
|
+
ipcRenderer.on("sanqian-chat:sessionResourceEvent", handler);
|
|
46
|
+
return () => ipcRenderer.removeListener("sanqian-chat:sessionResourceEvent", handler);
|
|
47
|
+
},
|
|
48
|
+
removeSessionResource: (fullId) => ipcRenderer.invoke("sanqian-chat:removeSessionResource", { fullId }),
|
|
49
|
+
// Focus
|
|
50
|
+
onFocusInput: (callback) => {
|
|
51
|
+
const handler = () => callback();
|
|
52
|
+
ipcRenderer.on("sanqian-chat:focusInput", handler);
|
|
53
|
+
return () => ipcRenderer.removeListener("sanqian-chat:focusInput", handler);
|
|
36
54
|
}
|
|
37
55
|
};
|
|
38
56
|
}
|
package/dist/core/index.d.mts
CHANGED
|
@@ -63,6 +63,7 @@ interface ChatUiStrings {
|
|
|
63
63
|
embedWindow: string;
|
|
64
64
|
collapseSidebar: string;
|
|
65
65
|
history: string;
|
|
66
|
+
remove: string;
|
|
66
67
|
}
|
|
67
68
|
type ChatThemeMode = 'light' | 'dark' | 'auto';
|
|
68
69
|
type ChatFontSize = 'small' | 'normal' | 'large' | 'extra-large';
|
|
@@ -389,6 +390,50 @@ interface AttachmentMenuItem {
|
|
|
389
390
|
/** Whether currently available (e.g., app connected) */
|
|
390
391
|
available?: boolean;
|
|
391
392
|
}
|
|
393
|
+
/**
|
|
394
|
+
* Session resource pushed by an app.
|
|
395
|
+
* Content is provided at push time (not fetched like attached_resources).
|
|
396
|
+
* Global scope - visible in all Chat UI instances, persists until app disconnects.
|
|
397
|
+
*/
|
|
398
|
+
interface SessionResource {
|
|
399
|
+
/** Resource ID (auto-generated if not provided) */
|
|
400
|
+
id?: string;
|
|
401
|
+
/** Display title (required) */
|
|
402
|
+
title: string;
|
|
403
|
+
/** Content (required, format controlled by app) */
|
|
404
|
+
content: string;
|
|
405
|
+
/** Optional summary for UI tooltip */
|
|
406
|
+
summary?: string;
|
|
407
|
+
/** Optional icon (emoji or URL) */
|
|
408
|
+
icon?: string;
|
|
409
|
+
/** Optional resource type for styling */
|
|
410
|
+
type?: ResourceType;
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* Stored session resource with full metadata (internal use)
|
|
414
|
+
*/
|
|
415
|
+
interface StoredSessionResource extends SessionResource {
|
|
416
|
+
/** Full ID: "appName:resourceId" */
|
|
417
|
+
fullId: string;
|
|
418
|
+
/** Source app name */
|
|
419
|
+
appName: string;
|
|
420
|
+
/** Push timestamp (ISO 8601) */
|
|
421
|
+
pushedAt: string;
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* Session resource event from backend
|
|
425
|
+
*/
|
|
426
|
+
type SessionResourceEvent = {
|
|
427
|
+
type: 'resource_pushed';
|
|
428
|
+
resource: StoredSessionResource;
|
|
429
|
+
} | {
|
|
430
|
+
type: 'resource_removed';
|
|
431
|
+
resourceId: string;
|
|
432
|
+
source: 'app' | 'user';
|
|
433
|
+
} | {
|
|
434
|
+
type: 'resources_cleared';
|
|
435
|
+
appName: string;
|
|
436
|
+
};
|
|
392
437
|
|
|
393
438
|
/**
|
|
394
439
|
* Chat Adapter Interface
|
|
@@ -476,6 +521,8 @@ interface ChatAdapter {
|
|
|
476
521
|
attachedContexts?: string[];
|
|
477
522
|
/** Attached resource references (e.g., ["sanqian-notes:notes:abc123"]) - for getById */
|
|
478
523
|
attachedResources?: string[];
|
|
524
|
+
/** Session resources pushed by apps (fullId list) */
|
|
525
|
+
sessionResources?: string[];
|
|
479
526
|
}): Promise<{
|
|
480
527
|
cancel: () => void;
|
|
481
528
|
}>;
|
|
@@ -489,6 +536,14 @@ interface ChatAdapter {
|
|
|
489
536
|
}>;
|
|
490
537
|
/** Subscribe to locale change events */
|
|
491
538
|
onLocaleChanged?(callback: (locale: string) => void): () => void;
|
|
539
|
+
/** Get current session resources from all connected apps */
|
|
540
|
+
getSessionResources?(): StoredSessionResource[];
|
|
541
|
+
/** Subscribe to session resource events (push/remove) */
|
|
542
|
+
onSessionResourceEvent?(callback: (event: SessionResourceEvent) => void): () => void;
|
|
543
|
+
/** Remove a session resource (user action from UI) */
|
|
544
|
+
removeSessionResource?(fullId: string): Promise<void>;
|
|
545
|
+
/** Subscribe to focus input events (e.g., from main process) */
|
|
546
|
+
onFocusInput?(callback: () => void): () => void;
|
|
492
547
|
cleanup?(): void;
|
|
493
548
|
}
|
|
494
549
|
/** SDK adapter config */
|
|
@@ -575,4 +630,4 @@ declare function parseToolCalls(toolCalls: unknown): ToolCall[] | undefined;
|
|
|
575
630
|
*/
|
|
576
631
|
declare function mergeConsecutiveAssistantMessages(rawMessages: ApiMessage[]): ChatMessage[];
|
|
577
632
|
|
|
578
|
-
export { type ApiMessage, type AttachConfig, type AttachPosition, type AttachState, type AttachedResource, type AttachmentMenuItem, type AttachmentMenuItemType, type ChatAdapter, type ChatAdapterConfig, type ChatFontSize, type ChatMessage, type ChatPanelConfig, type ChatPanelMode, type ChatPanelPosition, type ChatThemeMode, type ChatUiConfigSerializable, type ChatUiStrings, type ConnectionErrorCode, type ConnectionStatus, type ContextProviderInfo, type ConversationDetail, type ConversationInfo, type FloatingWindowConfig, type HitlInterruptData, type Locale, type MessageBlock, type MessageRole, type ResourcePickerItem, type ResourcePickerState, type SdkAdapterConfig, type SendMessage, type StreamEvent, type ToolCall, type ToolCallStatus, type WindowPosition, createChatAdapter, createSdkAdapter, mergeConsecutiveAssistantMessages, parseToolCalls };
|
|
633
|
+
export { type ApiMessage, type AttachConfig, type AttachPosition, type AttachState, type AttachedResource, type AttachmentMenuItem, type AttachmentMenuItemType, type ChatAdapter, type ChatAdapterConfig, type ChatFontSize, type ChatMessage, type ChatPanelConfig, type ChatPanelMode, type ChatPanelPosition, type ChatThemeMode, type ChatUiConfigSerializable, type ChatUiStrings, type ConnectionErrorCode, type ConnectionStatus, type ContextProviderInfo, type ConversationDetail, type ConversationInfo, type FloatingWindowConfig, type HitlInterruptData, type Locale, type MessageBlock, type MessageRole, type ResourcePickerItem, type ResourcePickerState, type SdkAdapterConfig, type SendMessage, type SessionResource, type SessionResourceEvent, type StoredSessionResource, type StreamEvent, type ToolCall, type ToolCallStatus, type WindowPosition, createChatAdapter, createSdkAdapter, mergeConsecutiveAssistantMessages, parseToolCalls };
|
package/dist/core/index.d.ts
CHANGED
|
@@ -63,6 +63,7 @@ interface ChatUiStrings {
|
|
|
63
63
|
embedWindow: string;
|
|
64
64
|
collapseSidebar: string;
|
|
65
65
|
history: string;
|
|
66
|
+
remove: string;
|
|
66
67
|
}
|
|
67
68
|
type ChatThemeMode = 'light' | 'dark' | 'auto';
|
|
68
69
|
type ChatFontSize = 'small' | 'normal' | 'large' | 'extra-large';
|
|
@@ -389,6 +390,50 @@ interface AttachmentMenuItem {
|
|
|
389
390
|
/** Whether currently available (e.g., app connected) */
|
|
390
391
|
available?: boolean;
|
|
391
392
|
}
|
|
393
|
+
/**
|
|
394
|
+
* Session resource pushed by an app.
|
|
395
|
+
* Content is provided at push time (not fetched like attached_resources).
|
|
396
|
+
* Global scope - visible in all Chat UI instances, persists until app disconnects.
|
|
397
|
+
*/
|
|
398
|
+
interface SessionResource {
|
|
399
|
+
/** Resource ID (auto-generated if not provided) */
|
|
400
|
+
id?: string;
|
|
401
|
+
/** Display title (required) */
|
|
402
|
+
title: string;
|
|
403
|
+
/** Content (required, format controlled by app) */
|
|
404
|
+
content: string;
|
|
405
|
+
/** Optional summary for UI tooltip */
|
|
406
|
+
summary?: string;
|
|
407
|
+
/** Optional icon (emoji or URL) */
|
|
408
|
+
icon?: string;
|
|
409
|
+
/** Optional resource type for styling */
|
|
410
|
+
type?: ResourceType;
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* Stored session resource with full metadata (internal use)
|
|
414
|
+
*/
|
|
415
|
+
interface StoredSessionResource extends SessionResource {
|
|
416
|
+
/** Full ID: "appName:resourceId" */
|
|
417
|
+
fullId: string;
|
|
418
|
+
/** Source app name */
|
|
419
|
+
appName: string;
|
|
420
|
+
/** Push timestamp (ISO 8601) */
|
|
421
|
+
pushedAt: string;
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* Session resource event from backend
|
|
425
|
+
*/
|
|
426
|
+
type SessionResourceEvent = {
|
|
427
|
+
type: 'resource_pushed';
|
|
428
|
+
resource: StoredSessionResource;
|
|
429
|
+
} | {
|
|
430
|
+
type: 'resource_removed';
|
|
431
|
+
resourceId: string;
|
|
432
|
+
source: 'app' | 'user';
|
|
433
|
+
} | {
|
|
434
|
+
type: 'resources_cleared';
|
|
435
|
+
appName: string;
|
|
436
|
+
};
|
|
392
437
|
|
|
393
438
|
/**
|
|
394
439
|
* Chat Adapter Interface
|
|
@@ -476,6 +521,8 @@ interface ChatAdapter {
|
|
|
476
521
|
attachedContexts?: string[];
|
|
477
522
|
/** Attached resource references (e.g., ["sanqian-notes:notes:abc123"]) - for getById */
|
|
478
523
|
attachedResources?: string[];
|
|
524
|
+
/** Session resources pushed by apps (fullId list) */
|
|
525
|
+
sessionResources?: string[];
|
|
479
526
|
}): Promise<{
|
|
480
527
|
cancel: () => void;
|
|
481
528
|
}>;
|
|
@@ -489,6 +536,14 @@ interface ChatAdapter {
|
|
|
489
536
|
}>;
|
|
490
537
|
/** Subscribe to locale change events */
|
|
491
538
|
onLocaleChanged?(callback: (locale: string) => void): () => void;
|
|
539
|
+
/** Get current session resources from all connected apps */
|
|
540
|
+
getSessionResources?(): StoredSessionResource[];
|
|
541
|
+
/** Subscribe to session resource events (push/remove) */
|
|
542
|
+
onSessionResourceEvent?(callback: (event: SessionResourceEvent) => void): () => void;
|
|
543
|
+
/** Remove a session resource (user action from UI) */
|
|
544
|
+
removeSessionResource?(fullId: string): Promise<void>;
|
|
545
|
+
/** Subscribe to focus input events (e.g., from main process) */
|
|
546
|
+
onFocusInput?(callback: () => void): () => void;
|
|
492
547
|
cleanup?(): void;
|
|
493
548
|
}
|
|
494
549
|
/** SDK adapter config */
|
|
@@ -575,4 +630,4 @@ declare function parseToolCalls(toolCalls: unknown): ToolCall[] | undefined;
|
|
|
575
630
|
*/
|
|
576
631
|
declare function mergeConsecutiveAssistantMessages(rawMessages: ApiMessage[]): ChatMessage[];
|
|
577
632
|
|
|
578
|
-
export { type ApiMessage, type AttachConfig, type AttachPosition, type AttachState, type AttachedResource, type AttachmentMenuItem, type AttachmentMenuItemType, type ChatAdapter, type ChatAdapterConfig, type ChatFontSize, type ChatMessage, type ChatPanelConfig, type ChatPanelMode, type ChatPanelPosition, type ChatThemeMode, type ChatUiConfigSerializable, type ChatUiStrings, type ConnectionErrorCode, type ConnectionStatus, type ContextProviderInfo, type ConversationDetail, type ConversationInfo, type FloatingWindowConfig, type HitlInterruptData, type Locale, type MessageBlock, type MessageRole, type ResourcePickerItem, type ResourcePickerState, type SdkAdapterConfig, type SendMessage, type StreamEvent, type ToolCall, type ToolCallStatus, type WindowPosition, createChatAdapter, createSdkAdapter, mergeConsecutiveAssistantMessages, parseToolCalls };
|
|
633
|
+
export { type ApiMessage, type AttachConfig, type AttachPosition, type AttachState, type AttachedResource, type AttachmentMenuItem, type AttachmentMenuItemType, type ChatAdapter, type ChatAdapterConfig, type ChatFontSize, type ChatMessage, type ChatPanelConfig, type ChatPanelMode, type ChatPanelPosition, type ChatThemeMode, type ChatUiConfigSerializable, type ChatUiStrings, type ConnectionErrorCode, type ConnectionStatus, type ContextProviderInfo, type ConversationDetail, type ConversationInfo, type FloatingWindowConfig, type HitlInterruptData, type Locale, type MessageBlock, type MessageRole, type ResourcePickerItem, type ResourcePickerState, type SdkAdapterConfig, type SendMessage, type SessionResource, type SessionResourceEvent, type StoredSessionResource, type StreamEvent, type ToolCall, type ToolCallStatus, type WindowPosition, createChatAdapter, createSdkAdapter, mergeConsecutiveAssistantMessages, parseToolCalls };
|
package/dist/core/index.js
CHANGED
|
@@ -413,7 +413,8 @@ function createChatAdapter(config) {
|
|
|
413
413
|
{
|
|
414
414
|
conversationId,
|
|
415
415
|
persistHistory: config.persistHistory ?? false,
|
|
416
|
-
attachedResources: options?.attachedResources
|
|
416
|
+
attachedResources: options?.attachedResources,
|
|
417
|
+
sessionResources: options?.sessionResources
|
|
417
418
|
}
|
|
418
419
|
);
|
|
419
420
|
return processStreamEvents(stream, onEvent, sdk, (id) => {
|
|
@@ -426,6 +427,31 @@ function createChatAdapter(config) {
|
|
|
426
427
|
if (id) {
|
|
427
428
|
sdkInstance.sendHitlResponse(id, response);
|
|
428
429
|
}
|
|
430
|
+
},
|
|
431
|
+
// Session Resources (delegated to shared helper)
|
|
432
|
+
...createSessionResourceMethods(() => sdkInstance)
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
function createSessionResourceMethods(getSdk) {
|
|
436
|
+
return {
|
|
437
|
+
getSessionResources() {
|
|
438
|
+
const sdk = getSdk();
|
|
439
|
+
return sdk?.getSessionResources?.() || [];
|
|
440
|
+
},
|
|
441
|
+
onSessionResourceEvent(callback) {
|
|
442
|
+
const sdk = getSdk();
|
|
443
|
+
if (!sdk) return () => {
|
|
444
|
+
};
|
|
445
|
+
const handler = (resourceId) => {
|
|
446
|
+
callback({ type: "resource_removed", resourceId, source: "user" });
|
|
447
|
+
};
|
|
448
|
+
sdk.on("resourceRemoved", handler);
|
|
449
|
+
return () => sdk.off("resourceRemoved", handler);
|
|
450
|
+
},
|
|
451
|
+
async removeSessionResource(fullId) {
|
|
452
|
+
const sdk = getSdk();
|
|
453
|
+
if (!sdk) return;
|
|
454
|
+
await sdk.removeSessionResource?.(fullId);
|
|
429
455
|
}
|
|
430
456
|
};
|
|
431
457
|
}
|
|
@@ -515,10 +541,10 @@ function processStreamEvents(stream, onEvent, sdk, setCurrentRunId) {
|
|
|
515
541
|
return {
|
|
516
542
|
cancel: () => {
|
|
517
543
|
controller.abort();
|
|
518
|
-
const
|
|
519
|
-
if (currentRunId && typeof
|
|
544
|
+
const extendedSdk = sdk;
|
|
545
|
+
if (currentRunId && typeof extendedSdk.cancelRun === "function") {
|
|
520
546
|
try {
|
|
521
|
-
|
|
547
|
+
extendedSdk.cancelRun(currentRunId);
|
|
522
548
|
} catch (e) {
|
|
523
549
|
console.warn("[chat adapter] Failed to cancel run:", e);
|
|
524
550
|
}
|
|
@@ -638,7 +664,8 @@ function createSdkAdapter(config) {
|
|
|
638
664
|
sdkMessages,
|
|
639
665
|
{
|
|
640
666
|
conversationId,
|
|
641
|
-
attachedResources: options?.attachedResources
|
|
667
|
+
attachedResources: options?.attachedResources,
|
|
668
|
+
sessionResources: options?.sessionResources
|
|
642
669
|
}
|
|
643
670
|
);
|
|
644
671
|
return processStreamEvents(stream, onEvent, sdk, (id) => {
|
|
@@ -652,7 +679,9 @@ function createSdkAdapter(config) {
|
|
|
652
679
|
if (id) {
|
|
653
680
|
sdk.sendHitlResponse(id, response);
|
|
654
681
|
}
|
|
655
|
-
}
|
|
682
|
+
},
|
|
683
|
+
// Session Resources (delegated to shared helper)
|
|
684
|
+
...createSessionResourceMethods(config.getSdk)
|
|
656
685
|
};
|
|
657
686
|
}
|
|
658
687
|
// Annotate the CommonJS export names for ESM import in node:
|
package/dist/core/index.mjs
CHANGED
|
@@ -374,7 +374,8 @@ function createChatAdapter(config) {
|
|
|
374
374
|
{
|
|
375
375
|
conversationId,
|
|
376
376
|
persistHistory: config.persistHistory ?? false,
|
|
377
|
-
attachedResources: options?.attachedResources
|
|
377
|
+
attachedResources: options?.attachedResources,
|
|
378
|
+
sessionResources: options?.sessionResources
|
|
378
379
|
}
|
|
379
380
|
);
|
|
380
381
|
return processStreamEvents(stream, onEvent, sdk, (id) => {
|
|
@@ -387,6 +388,31 @@ function createChatAdapter(config) {
|
|
|
387
388
|
if (id) {
|
|
388
389
|
sdkInstance.sendHitlResponse(id, response);
|
|
389
390
|
}
|
|
391
|
+
},
|
|
392
|
+
// Session Resources (delegated to shared helper)
|
|
393
|
+
...createSessionResourceMethods(() => sdkInstance)
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
function createSessionResourceMethods(getSdk) {
|
|
397
|
+
return {
|
|
398
|
+
getSessionResources() {
|
|
399
|
+
const sdk = getSdk();
|
|
400
|
+
return sdk?.getSessionResources?.() || [];
|
|
401
|
+
},
|
|
402
|
+
onSessionResourceEvent(callback) {
|
|
403
|
+
const sdk = getSdk();
|
|
404
|
+
if (!sdk) return () => {
|
|
405
|
+
};
|
|
406
|
+
const handler = (resourceId) => {
|
|
407
|
+
callback({ type: "resource_removed", resourceId, source: "user" });
|
|
408
|
+
};
|
|
409
|
+
sdk.on("resourceRemoved", handler);
|
|
410
|
+
return () => sdk.off("resourceRemoved", handler);
|
|
411
|
+
},
|
|
412
|
+
async removeSessionResource(fullId) {
|
|
413
|
+
const sdk = getSdk();
|
|
414
|
+
if (!sdk) return;
|
|
415
|
+
await sdk.removeSessionResource?.(fullId);
|
|
390
416
|
}
|
|
391
417
|
};
|
|
392
418
|
}
|
|
@@ -476,10 +502,10 @@ function processStreamEvents(stream, onEvent, sdk, setCurrentRunId) {
|
|
|
476
502
|
return {
|
|
477
503
|
cancel: () => {
|
|
478
504
|
controller.abort();
|
|
479
|
-
const
|
|
480
|
-
if (currentRunId && typeof
|
|
505
|
+
const extendedSdk = sdk;
|
|
506
|
+
if (currentRunId && typeof extendedSdk.cancelRun === "function") {
|
|
481
507
|
try {
|
|
482
|
-
|
|
508
|
+
extendedSdk.cancelRun(currentRunId);
|
|
483
509
|
} catch (e) {
|
|
484
510
|
console.warn("[chat adapter] Failed to cancel run:", e);
|
|
485
511
|
}
|
|
@@ -599,7 +625,8 @@ function createSdkAdapter(config) {
|
|
|
599
625
|
sdkMessages,
|
|
600
626
|
{
|
|
601
627
|
conversationId,
|
|
602
|
-
attachedResources: options?.attachedResources
|
|
628
|
+
attachedResources: options?.attachedResources,
|
|
629
|
+
sessionResources: options?.sessionResources
|
|
603
630
|
}
|
|
604
631
|
);
|
|
605
632
|
return processStreamEvents(stream, onEvent, sdk, (id) => {
|
|
@@ -613,7 +640,9 @@ function createSdkAdapter(config) {
|
|
|
613
640
|
if (id) {
|
|
614
641
|
sdk.sendHitlResponse(id, response);
|
|
615
642
|
}
|
|
616
|
-
}
|
|
643
|
+
},
|
|
644
|
+
// Session Resources (delegated to shared helper)
|
|
645
|
+
...createSessionResourceMethods(config.getSdk)
|
|
617
646
|
};
|
|
618
647
|
}
|
|
619
648
|
export {
|
package/dist/main/index.d.mts
CHANGED
|
@@ -192,7 +192,7 @@ interface AppEmbeddingConfig {
|
|
|
192
192
|
/**
|
|
193
193
|
* Events emitted by SanqianAppClient
|
|
194
194
|
*/
|
|
195
|
-
type AppClientEvent = 'connected' | 'registered' | 'disconnected' | 'error' | 'tool_call';
|
|
195
|
+
type AppClientEvent = 'connected' | 'registered' | 'disconnected' | 'error' | 'tool_call' | 'resourcePushed' | 'resourceRemoved';
|
|
196
196
|
/**
|
|
197
197
|
* Event handler types
|
|
198
198
|
*/
|
|
@@ -205,6 +205,8 @@ interface AppClientEventHandlers {
|
|
|
205
205
|
name: string;
|
|
206
206
|
arguments: Record<string, unknown>;
|
|
207
207
|
}) => void;
|
|
208
|
+
resourcePushed: (resource: _yushaw_sanqian_sdk.StoredSessionResource) => void;
|
|
209
|
+
resourceRemoved: (resourceId: string) => void;
|
|
208
210
|
}
|
|
209
211
|
|
|
210
212
|
/**
|
|
@@ -284,6 +286,10 @@ declare class SanqianAppClient {
|
|
|
284
286
|
* Subscribe to client events
|
|
285
287
|
*/
|
|
286
288
|
on<E extends AppClientEvent>(event: E, handler: AppClientEventHandlers[E]): this;
|
|
289
|
+
/**
|
|
290
|
+
* Unsubscribe from client events
|
|
291
|
+
*/
|
|
292
|
+
off<E extends AppClientEvent>(event: E, handler: AppClientEventHandlers[E]): this;
|
|
287
293
|
/**
|
|
288
294
|
* Remove all event listeners
|
|
289
295
|
*/
|
|
@@ -356,6 +362,44 @@ declare class SanqianAppClient {
|
|
|
356
362
|
* List all available agents (not just own agents)
|
|
357
363
|
*/
|
|
358
364
|
listAvailableAgents(): Promise<_yushaw_sanqian_sdk.AgentCapability[]>;
|
|
365
|
+
/**
|
|
366
|
+
* Push a temporary context resource to Sanqian Chat
|
|
367
|
+
* Resources are displayed as chips in the Chat UI and included in LLM context
|
|
368
|
+
*
|
|
369
|
+
* @example
|
|
370
|
+
* ```typescript
|
|
371
|
+
* const resource = await client.pushResource({
|
|
372
|
+
* id: 'editor-selection',
|
|
373
|
+
* title: 'Selected Text',
|
|
374
|
+
* content: '<selection>...</selection>',
|
|
375
|
+
* summary: 'First 50 chars...',
|
|
376
|
+
* icon: '📝',
|
|
377
|
+
* type: 'selection',
|
|
378
|
+
* });
|
|
379
|
+
* ```
|
|
380
|
+
*/
|
|
381
|
+
pushResource(resource: _yushaw_sanqian_sdk.SessionResource): Promise<_yushaw_sanqian_sdk.StoredSessionResource>;
|
|
382
|
+
/**
|
|
383
|
+
* Remove a session resource by its full ID
|
|
384
|
+
*
|
|
385
|
+
* @example
|
|
386
|
+
* ```typescript
|
|
387
|
+
* await client.removeResource('my-app:editor-selection');
|
|
388
|
+
* ```
|
|
389
|
+
*/
|
|
390
|
+
removeResource(resourceId: string): Promise<void>;
|
|
391
|
+
/**
|
|
392
|
+
* Get all current session resources
|
|
393
|
+
*
|
|
394
|
+
* @example
|
|
395
|
+
* ```typescript
|
|
396
|
+
* const resources = client.getSessionResources();
|
|
397
|
+
* for (const r of resources) {
|
|
398
|
+
* console.log(`${r.fullId}: ${r.title}`);
|
|
399
|
+
* }
|
|
400
|
+
* ```
|
|
401
|
+
*/
|
|
402
|
+
getSessionResources(): _yushaw_sanqian_sdk.StoredSessionResource[];
|
|
359
403
|
/**
|
|
360
404
|
* Get the underlying SDK instance
|
|
361
405
|
* @internal This is for internal use by other sanqian-chat components
|
|
@@ -425,6 +469,7 @@ interface ChatUiStrings {
|
|
|
425
469
|
embedWindow: string;
|
|
426
470
|
collapseSidebar: string;
|
|
427
471
|
history: string;
|
|
472
|
+
remove: string;
|
|
428
473
|
}
|
|
429
474
|
type ChatThemeMode = 'light' | 'dark' | 'auto';
|
|
430
475
|
type ChatFontSize = 'small' | 'normal' | 'large' | 'extra-large';
|
|
@@ -715,6 +760,7 @@ declare class ChatPanel {
|
|
|
715
760
|
private registeredShortcuts;
|
|
716
761
|
private stateSaveTimer;
|
|
717
762
|
private activeStreams;
|
|
763
|
+
private sessionResourceCleanup;
|
|
718
764
|
constructor(config: ChatPanelConfig);
|
|
719
765
|
private hostResizeHandler;
|
|
720
766
|
private setupHostWindowListeners;
|
|
@@ -727,6 +773,18 @@ declare class ChatPanel {
|
|
|
727
773
|
* Show panel
|
|
728
774
|
*/
|
|
729
775
|
show(): void;
|
|
776
|
+
/**
|
|
777
|
+
* Focus the chat input
|
|
778
|
+
*
|
|
779
|
+
* Industry best practice (VS Code, etc.):
|
|
780
|
+
* 1. Focus the window (for floating mode)
|
|
781
|
+
* 2. Focus webContents to transfer focus to BrowserView
|
|
782
|
+
* 3. Send message to renderer to focus the input element
|
|
783
|
+
*
|
|
784
|
+
* Note: webContents.focus() is crucial for BrowserView - without it,
|
|
785
|
+
* focus stays in the main content area even if window has focus.
|
|
786
|
+
*/
|
|
787
|
+
focusInput(): void;
|
|
730
788
|
/**
|
|
731
789
|
* Hide panel
|
|
732
790
|
*/
|
|
@@ -834,6 +892,11 @@ declare class ChatPanel {
|
|
|
834
892
|
private scheduleSaveState;
|
|
835
893
|
private saveState;
|
|
836
894
|
private getSdk;
|
|
895
|
+
/**
|
|
896
|
+
* Setup session resource event forwarding from SDK to renderer
|
|
897
|
+
* Called when SDK becomes available (on connect)
|
|
898
|
+
*/
|
|
899
|
+
private setupSessionResourceEvents;
|
|
837
900
|
private setupIpcHandlers;
|
|
838
901
|
private cleanupIpcHandlers;
|
|
839
902
|
}
|
package/dist/main/index.d.ts
CHANGED
|
@@ -192,7 +192,7 @@ interface AppEmbeddingConfig {
|
|
|
192
192
|
/**
|
|
193
193
|
* Events emitted by SanqianAppClient
|
|
194
194
|
*/
|
|
195
|
-
type AppClientEvent = 'connected' | 'registered' | 'disconnected' | 'error' | 'tool_call';
|
|
195
|
+
type AppClientEvent = 'connected' | 'registered' | 'disconnected' | 'error' | 'tool_call' | 'resourcePushed' | 'resourceRemoved';
|
|
196
196
|
/**
|
|
197
197
|
* Event handler types
|
|
198
198
|
*/
|
|
@@ -205,6 +205,8 @@ interface AppClientEventHandlers {
|
|
|
205
205
|
name: string;
|
|
206
206
|
arguments: Record<string, unknown>;
|
|
207
207
|
}) => void;
|
|
208
|
+
resourcePushed: (resource: _yushaw_sanqian_sdk.StoredSessionResource) => void;
|
|
209
|
+
resourceRemoved: (resourceId: string) => void;
|
|
208
210
|
}
|
|
209
211
|
|
|
210
212
|
/**
|
|
@@ -284,6 +286,10 @@ declare class SanqianAppClient {
|
|
|
284
286
|
* Subscribe to client events
|
|
285
287
|
*/
|
|
286
288
|
on<E extends AppClientEvent>(event: E, handler: AppClientEventHandlers[E]): this;
|
|
289
|
+
/**
|
|
290
|
+
* Unsubscribe from client events
|
|
291
|
+
*/
|
|
292
|
+
off<E extends AppClientEvent>(event: E, handler: AppClientEventHandlers[E]): this;
|
|
287
293
|
/**
|
|
288
294
|
* Remove all event listeners
|
|
289
295
|
*/
|
|
@@ -356,6 +362,44 @@ declare class SanqianAppClient {
|
|
|
356
362
|
* List all available agents (not just own agents)
|
|
357
363
|
*/
|
|
358
364
|
listAvailableAgents(): Promise<_yushaw_sanqian_sdk.AgentCapability[]>;
|
|
365
|
+
/**
|
|
366
|
+
* Push a temporary context resource to Sanqian Chat
|
|
367
|
+
* Resources are displayed as chips in the Chat UI and included in LLM context
|
|
368
|
+
*
|
|
369
|
+
* @example
|
|
370
|
+
* ```typescript
|
|
371
|
+
* const resource = await client.pushResource({
|
|
372
|
+
* id: 'editor-selection',
|
|
373
|
+
* title: 'Selected Text',
|
|
374
|
+
* content: '<selection>...</selection>',
|
|
375
|
+
* summary: 'First 50 chars...',
|
|
376
|
+
* icon: '📝',
|
|
377
|
+
* type: 'selection',
|
|
378
|
+
* });
|
|
379
|
+
* ```
|
|
380
|
+
*/
|
|
381
|
+
pushResource(resource: _yushaw_sanqian_sdk.SessionResource): Promise<_yushaw_sanqian_sdk.StoredSessionResource>;
|
|
382
|
+
/**
|
|
383
|
+
* Remove a session resource by its full ID
|
|
384
|
+
*
|
|
385
|
+
* @example
|
|
386
|
+
* ```typescript
|
|
387
|
+
* await client.removeResource('my-app:editor-selection');
|
|
388
|
+
* ```
|
|
389
|
+
*/
|
|
390
|
+
removeResource(resourceId: string): Promise<void>;
|
|
391
|
+
/**
|
|
392
|
+
* Get all current session resources
|
|
393
|
+
*
|
|
394
|
+
* @example
|
|
395
|
+
* ```typescript
|
|
396
|
+
* const resources = client.getSessionResources();
|
|
397
|
+
* for (const r of resources) {
|
|
398
|
+
* console.log(`${r.fullId}: ${r.title}`);
|
|
399
|
+
* }
|
|
400
|
+
* ```
|
|
401
|
+
*/
|
|
402
|
+
getSessionResources(): _yushaw_sanqian_sdk.StoredSessionResource[];
|
|
359
403
|
/**
|
|
360
404
|
* Get the underlying SDK instance
|
|
361
405
|
* @internal This is for internal use by other sanqian-chat components
|
|
@@ -425,6 +469,7 @@ interface ChatUiStrings {
|
|
|
425
469
|
embedWindow: string;
|
|
426
470
|
collapseSidebar: string;
|
|
427
471
|
history: string;
|
|
472
|
+
remove: string;
|
|
428
473
|
}
|
|
429
474
|
type ChatThemeMode = 'light' | 'dark' | 'auto';
|
|
430
475
|
type ChatFontSize = 'small' | 'normal' | 'large' | 'extra-large';
|
|
@@ -715,6 +760,7 @@ declare class ChatPanel {
|
|
|
715
760
|
private registeredShortcuts;
|
|
716
761
|
private stateSaveTimer;
|
|
717
762
|
private activeStreams;
|
|
763
|
+
private sessionResourceCleanup;
|
|
718
764
|
constructor(config: ChatPanelConfig);
|
|
719
765
|
private hostResizeHandler;
|
|
720
766
|
private setupHostWindowListeners;
|
|
@@ -727,6 +773,18 @@ declare class ChatPanel {
|
|
|
727
773
|
* Show panel
|
|
728
774
|
*/
|
|
729
775
|
show(): void;
|
|
776
|
+
/**
|
|
777
|
+
* Focus the chat input
|
|
778
|
+
*
|
|
779
|
+
* Industry best practice (VS Code, etc.):
|
|
780
|
+
* 1. Focus the window (for floating mode)
|
|
781
|
+
* 2. Focus webContents to transfer focus to BrowserView
|
|
782
|
+
* 3. Send message to renderer to focus the input element
|
|
783
|
+
*
|
|
784
|
+
* Note: webContents.focus() is crucial for BrowserView - without it,
|
|
785
|
+
* focus stays in the main content area even if window has focus.
|
|
786
|
+
*/
|
|
787
|
+
focusInput(): void;
|
|
730
788
|
/**
|
|
731
789
|
* Hide panel
|
|
732
790
|
*/
|
|
@@ -834,6 +892,11 @@ declare class ChatPanel {
|
|
|
834
892
|
private scheduleSaveState;
|
|
835
893
|
private saveState;
|
|
836
894
|
private getSdk;
|
|
895
|
+
/**
|
|
896
|
+
* Setup session resource event forwarding from SDK to renderer
|
|
897
|
+
* Called when SDK becomes available (on connect)
|
|
898
|
+
*/
|
|
899
|
+
private setupSessionResourceEvents;
|
|
837
900
|
private setupIpcHandlers;
|
|
838
901
|
private cleanupIpcHandlers;
|
|
839
902
|
}
|