dsh-side-chat-plus 0.3.4 → 0.4.0-alpha.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.
- package/README.md +9 -1
- package/README.zh.md +7 -1
- package/dsh.plugin.json +2 -2
- package/lib/client-registry.js +143 -113
- package/lib/client-registry.js.map +1 -1
- package/lib/client.js +141 -111
- package/lib/client.js.map +1 -1
- package/lib/index.js +60 -25
- package/lib/types/client/api.d.ts +1 -0
- package/lib/types/client/locales.d.ts +2 -0
- package/lib/types/context-types.d.ts +15 -16
- package/package.json +39 -38
- package/src/client/api.ts +1 -1
- package/src/client/index.tsx +52 -21
- package/src/client/locales.ts +2 -0
- package/src/context-types.ts +13 -18
- package/src/index.ts +60 -22
package/src/index.ts
CHANGED
|
@@ -23,6 +23,7 @@ import type {
|
|
|
23
23
|
SideImageAttachmentRef,
|
|
24
24
|
SideInstallModelSelection,
|
|
25
25
|
SideModelSelectionRef,
|
|
26
|
+
SidePresetOption,
|
|
26
27
|
SideSession,
|
|
27
28
|
SideSessionEvent,
|
|
28
29
|
} from './context-types.ts'
|
|
@@ -40,7 +41,6 @@ export const inject = [
|
|
|
40
41
|
'agents',
|
|
41
42
|
'workspaceRegistry',
|
|
42
43
|
'sessionQuery',
|
|
43
|
-
'sandboxPolicy',
|
|
44
44
|
'permissionPresets',
|
|
45
45
|
'agentPresets',
|
|
46
46
|
'llm',
|
|
@@ -181,17 +181,6 @@ function openTurnStart(events: readonly SideSessionEvent[]): number | undefined
|
|
|
181
181
|
return lastStart
|
|
182
182
|
}
|
|
183
183
|
|
|
184
|
-
/**
|
|
185
|
-
* Read a session's event log across DSH versions: 0.1.5+ exposes
|
|
186
|
-
* `snapshotEvents()`; 0.1.2-era sessions carried a plain `events` getter.
|
|
187
|
-
*/
|
|
188
|
-
function sessionEvents(session: SideSession): readonly SideSessionEvent[] {
|
|
189
|
-
if (typeof session.snapshotEvents === 'function') {
|
|
190
|
-
return session.snapshotEvents()
|
|
191
|
-
}
|
|
192
|
-
return session.events ?? []
|
|
193
|
-
}
|
|
194
|
-
|
|
195
184
|
/** Schemastery schema for the user-facing preferences (validated by the settings service). */
|
|
196
185
|
const PrefsSchema: z<SubchatPrefs> = z.object({
|
|
197
186
|
lookupDefault: z.boolean().default(SUBCHAT_PREFS_DEFAULTS.lookupDefault),
|
|
@@ -327,11 +316,20 @@ function buildApi(ctx: Context, sideChats: Map<string, SidechatRecord>, getSetti
|
|
|
327
316
|
return { executed: result !== undefined }
|
|
328
317
|
}
|
|
329
318
|
|
|
319
|
+
/**
|
|
320
|
+
* Read a side chat's event log through the session-query service. DSH 0.1.6
|
|
321
|
+
* deprecated the Session's synchronous event getters (`snapshotEvents`,
|
|
322
|
+
* `eventAt`, `ownEvents`); `readSession` is the live-preferred asynchronous
|
|
323
|
+
* read that supersedes them, and the transcript routes already use it.
|
|
324
|
+
*/
|
|
325
|
+
const sessionEvents = async (sessionId: string): Promise<readonly SideSessionEvent[]> =>
|
|
326
|
+
(await ctx.sessionQuery.readSession(sessionId)).events
|
|
327
|
+
|
|
330
328
|
/** Fold one side-chat agent's plan/goal state for its composer chrome. */
|
|
331
|
-
const state = (payload: unknown): { plan: { active: boolean; pending: boolean }; goal: { id: string; objective: string } | null } => {
|
|
329
|
+
const state = async (payload: unknown): Promise<{ plan: { active: boolean; pending: boolean }; goal: { id: string; objective: string } | null }> => {
|
|
332
330
|
const childId = requireString(payload, 'childId')
|
|
333
|
-
|
|
334
|
-
const events = sessionEvents(
|
|
331
|
+
childOf(childId)
|
|
332
|
+
const events = await sessionEvents(childId)
|
|
335
333
|
// Plan fold mirrors dsh-plan-mode's `plan` projection.
|
|
336
334
|
let planActive = false
|
|
337
335
|
let planWanted: boolean | null = null
|
|
@@ -479,7 +477,7 @@ function buildApi(ctx: Context, sideChats: Map<string, SidechatRecord>, getSetti
|
|
|
479
477
|
}
|
|
480
478
|
|
|
481
479
|
/** List the side chats launched by one parent conversation. */
|
|
482
|
-
const list = (payload: unknown): { items: Array<{ childId: string; running: boolean; runningSince?: number }> } => {
|
|
480
|
+
const list = async (payload: unknown): Promise<{ items: Array<{ childId: string; running: boolean; runningSince?: number }> }> => {
|
|
483
481
|
const parentSessionId = requireString(payload, 'parentSessionId')
|
|
484
482
|
const items: Array<{ childId: string; running: boolean; runningSince?: number }> = []
|
|
485
483
|
for (const record of sideChats.values()) {
|
|
@@ -494,7 +492,8 @@ function buildApi(ctx: Context, sideChats: Map<string, SidechatRecord>, getSetti
|
|
|
494
492
|
// back to the open-turn event scan.
|
|
495
493
|
const status = (agent as { status?: string }).status
|
|
496
494
|
const statusRunning = status === 'running'
|
|
497
|
-
|
|
495
|
+
// Only the status-less fallback pays for a log read.
|
|
496
|
+
const eventRunningSince = status === undefined ? openTurnStart(await sessionEvents(record.childId)) : undefined
|
|
498
497
|
const running = statusRunning || (status === undefined && eventRunningSince !== undefined)
|
|
499
498
|
const runningSince = running ? (eventRunningSince ?? Date.now()) : undefined
|
|
500
499
|
items.push({
|
|
@@ -522,7 +521,7 @@ function buildApi(ctx: Context, sideChats: Map<string, SidechatRecord>, getSetti
|
|
|
522
521
|
}
|
|
523
522
|
|
|
524
523
|
/** The deployment-resolved image policy (for client-side fast-path checks). */
|
|
525
|
-
const limits = (): { mediaTypes: string[]; maxImageBytes: number; maxImagesPerMessage: number; maxMessageImageBytes: number; maxImagePixels: number } => {
|
|
524
|
+
const limits = (): { mediaTypes: string[]; maxImageBytes: number; maxImagesPerMessage: number; maxMessageImageBytes: number; maxImagePixels: number; maxImageDimension?: number } => {
|
|
526
525
|
const l = ctx.attachments.imageLimits
|
|
527
526
|
return {
|
|
528
527
|
mediaTypes: [...l.mediaTypes],
|
|
@@ -530,6 +529,8 @@ function buildApi(ctx: Context, sideChats: Map<string, SidechatRecord>, getSetti
|
|
|
530
529
|
maxImagesPerMessage: l.maxImagesPerMessage,
|
|
531
530
|
maxMessageImageBytes: l.maxMessageImageBytes,
|
|
532
531
|
maxImagePixels: l.maxImagePixels,
|
|
532
|
+
// Added in 0.1.6; earlier lines leave it absent so the client skips the check.
|
|
533
|
+
...(l.maxImageDimension === undefined ? {} : { maxImageDimension: l.maxImageDimension }),
|
|
533
534
|
}
|
|
534
535
|
}
|
|
535
536
|
|
|
@@ -718,11 +719,31 @@ function buildApi(ctx: Context, sideChats: Map<string, SidechatRecord>, getSetti
|
|
|
718
719
|
|
|
719
720
|
/** Permission-preset options for the side-chat selector. */
|
|
720
721
|
const permissions = (): { options: Array<{ value: string; name: string; description?: string }>; current: string } => {
|
|
721
|
-
const
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
722
|
+
const presets = ctx.permissionPresets
|
|
723
|
+
const toOption = (o: SidePresetOption): { value: string; name: string; description?: string } => ({
|
|
724
|
+
value: o.value,
|
|
725
|
+
name: o.name,
|
|
726
|
+
...(o.description === undefined ? {} : { description: o.description }),
|
|
727
|
+
})
|
|
728
|
+
// 0.1.6 split the combined `selectFor(knobState)` into a process-level
|
|
729
|
+
// `catalog()` plus a separate current value. Prefer the new face and fall
|
|
730
|
+
// back to the old one so both release lines serve this route.
|
|
731
|
+
const catalog = presets.catalog
|
|
732
|
+
if (typeof catalog === 'function') {
|
|
733
|
+
return {
|
|
734
|
+
options: catalog.call(presets).options.map(toOption),
|
|
735
|
+
current: presets.defaultPreset ?? 'custom',
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
const selectFor = presets.selectFor
|
|
739
|
+
if (typeof selectFor === 'function') {
|
|
740
|
+
const select = selectFor.call(presets, {})
|
|
741
|
+
return {
|
|
742
|
+
options: select.options.map(toOption),
|
|
743
|
+
current: select.currentValue,
|
|
744
|
+
}
|
|
725
745
|
}
|
|
746
|
+
throw new SidechatError('permissions-unavailable', 'the permission-presets service exposes neither catalog() nor selectFor()', 503)
|
|
726
747
|
}
|
|
727
748
|
|
|
728
749
|
return {
|
|
@@ -826,6 +847,23 @@ export function apply(ctx: Context): void {
|
|
|
826
847
|
}
|
|
827
848
|
}, 'dsh-side-chat: dispose side chats')
|
|
828
849
|
|
|
850
|
+
// DSH 0.1.6 lists archived sessions in Settings and lets the user restore
|
|
851
|
+
// one. A side chat is archived precisely so it stays out of the session
|
|
852
|
+
// list, so at activation re-archive every recorded side chat that a restore
|
|
853
|
+
// (or an older run) left visible again. Best-effort: records whose session
|
|
854
|
+
// no longer exists are simply skipped.
|
|
855
|
+
ctx.effect(() => {
|
|
856
|
+
void (async () => {
|
|
857
|
+
for (const record of await readRecords()) {
|
|
858
|
+
try {
|
|
859
|
+
await ctx.workspaceRegistry.archiveSession(record.childId)
|
|
860
|
+
} catch {
|
|
861
|
+
// Unknown/expired ids are expected as the record list ages out.
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
})()
|
|
865
|
+
}, 'dsh-side-chat: re-archive recorded side chats')
|
|
866
|
+
|
|
829
867
|
ctx.effect(() => ctx.webServer.register({
|
|
830
868
|
kind: 'prefix',
|
|
831
869
|
path: '/sidechat/api',
|