@nextclaw/server 0.6.7 → 0.6.9
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/dist/index.d.ts +76 -2
- package/dist/index.js +278 -3
- package/package.json +5 -4
package/dist/index.d.ts
CHANGED
|
@@ -54,6 +54,48 @@ type ProviderConnectionTestResult = {
|
|
|
54
54
|
latencyMs: number;
|
|
55
55
|
message: string;
|
|
56
56
|
};
|
|
57
|
+
type SearchProviderName = "bocha" | "brave";
|
|
58
|
+
type BochaFreshnessValue = "noLimit" | "oneDay" | "oneWeek" | "oneMonth" | "oneYear" | string;
|
|
59
|
+
type SearchProviderConfigView = {
|
|
60
|
+
enabled: boolean;
|
|
61
|
+
apiKeySet: boolean;
|
|
62
|
+
apiKeyMasked?: string;
|
|
63
|
+
baseUrl: string;
|
|
64
|
+
docsUrl?: string;
|
|
65
|
+
summary?: boolean;
|
|
66
|
+
freshness?: BochaFreshnessValue;
|
|
67
|
+
};
|
|
68
|
+
type SearchConfigView = {
|
|
69
|
+
provider: SearchProviderName;
|
|
70
|
+
enabledProviders: SearchProviderName[];
|
|
71
|
+
defaults: {
|
|
72
|
+
maxResults: number;
|
|
73
|
+
};
|
|
74
|
+
providers: {
|
|
75
|
+
bocha: SearchProviderConfigView;
|
|
76
|
+
brave: SearchProviderConfigView;
|
|
77
|
+
};
|
|
78
|
+
};
|
|
79
|
+
type SearchConfigUpdate = {
|
|
80
|
+
provider?: SearchProviderName;
|
|
81
|
+
enabledProviders?: SearchProviderName[];
|
|
82
|
+
defaults?: {
|
|
83
|
+
maxResults?: number;
|
|
84
|
+
};
|
|
85
|
+
providers?: {
|
|
86
|
+
bocha?: {
|
|
87
|
+
apiKey?: string | null;
|
|
88
|
+
baseUrl?: string | null;
|
|
89
|
+
docsUrl?: string | null;
|
|
90
|
+
summary?: boolean;
|
|
91
|
+
freshness?: BochaFreshnessValue | null;
|
|
92
|
+
};
|
|
93
|
+
brave?: {
|
|
94
|
+
apiKey?: string | null;
|
|
95
|
+
baseUrl?: string | null;
|
|
96
|
+
};
|
|
97
|
+
};
|
|
98
|
+
};
|
|
57
99
|
type ProviderAuthStartResult = {
|
|
58
100
|
provider: string;
|
|
59
101
|
kind: "device_code";
|
|
@@ -117,6 +159,8 @@ type SessionEntryView = {
|
|
|
117
159
|
updatedAt: string;
|
|
118
160
|
label?: string;
|
|
119
161
|
preferredModel?: string;
|
|
162
|
+
sessionType: string;
|
|
163
|
+
sessionTypeMutable: boolean;
|
|
120
164
|
messageCount: number;
|
|
121
165
|
lastRole?: string;
|
|
122
166
|
lastTimestamp?: string;
|
|
@@ -144,6 +188,8 @@ type SessionHistoryView = {
|
|
|
144
188
|
key: string;
|
|
145
189
|
totalMessages: number;
|
|
146
190
|
totalEvents: number;
|
|
191
|
+
sessionType: string;
|
|
192
|
+
sessionTypeMutable: boolean;
|
|
147
193
|
metadata: Record<string, unknown>;
|
|
148
194
|
messages: SessionMessageView[];
|
|
149
195
|
events: SessionEventView[];
|
|
@@ -151,6 +197,7 @@ type SessionHistoryView = {
|
|
|
151
197
|
type SessionPatchUpdate = {
|
|
152
198
|
label?: string | null;
|
|
153
199
|
preferredModel?: string | null;
|
|
200
|
+
sessionType?: string | null;
|
|
154
201
|
clearHistory?: boolean;
|
|
155
202
|
};
|
|
156
203
|
type CronScheduleView = {
|
|
@@ -300,6 +347,14 @@ type ChatCapabilitiesView = {
|
|
|
300
347
|
stopSupported: boolean;
|
|
301
348
|
stopReason?: string;
|
|
302
349
|
};
|
|
350
|
+
type ChatSessionTypeOptionView = {
|
|
351
|
+
value: string;
|
|
352
|
+
label: string;
|
|
353
|
+
};
|
|
354
|
+
type ChatSessionTypesView = {
|
|
355
|
+
defaultType: string;
|
|
356
|
+
options: ChatSessionTypeOptionView[];
|
|
357
|
+
};
|
|
303
358
|
type ChatCommandOptionView = {
|
|
304
359
|
name: string;
|
|
305
360
|
description: string;
|
|
@@ -363,6 +418,7 @@ type UiChatRuntime = {
|
|
|
363
418
|
limit?: number;
|
|
364
419
|
}) => Promise<ChatRunListView> | ChatRunListView;
|
|
365
420
|
getCapabilities?: (params: Pick<ChatTurnRequest, "sessionKey" | "agentId">) => Promise<ChatCapabilitiesView> | ChatCapabilitiesView;
|
|
421
|
+
listSessionTypes?: () => Promise<ChatSessionTypesView> | ChatSessionTypesView;
|
|
366
422
|
stopTurn?: (params: ChatTurnStopRequest) => Promise<ChatTurnStopResult> | ChatTurnStopResult;
|
|
367
423
|
};
|
|
368
424
|
type ConfigView = {
|
|
@@ -391,6 +447,7 @@ type ConfigView = {
|
|
|
391
447
|
};
|
|
392
448
|
};
|
|
393
449
|
providers: Record<string, ProviderConfigView>;
|
|
450
|
+
search: SearchConfigView;
|
|
394
451
|
channels: Record<string, Record<string, unknown>>;
|
|
395
452
|
bindings?: AgentBindingView[];
|
|
396
453
|
session?: SessionConfigView;
|
|
@@ -451,8 +508,17 @@ type ChannelSpecView = {
|
|
|
451
508
|
zh?: string;
|
|
452
509
|
};
|
|
453
510
|
};
|
|
511
|
+
type SearchProviderSpecView = {
|
|
512
|
+
name: SearchProviderName;
|
|
513
|
+
displayName: string;
|
|
514
|
+
description: string;
|
|
515
|
+
docsUrl?: string;
|
|
516
|
+
isDefault?: boolean;
|
|
517
|
+
supportsSummary?: boolean;
|
|
518
|
+
};
|
|
454
519
|
type ConfigMetaView = {
|
|
455
520
|
providers: ProviderSpecView[];
|
|
521
|
+
search: SearchProviderSpecView[];
|
|
456
522
|
channels: ChannelSpecView[];
|
|
457
523
|
};
|
|
458
524
|
type ConfigUiHint = {
|
|
@@ -773,6 +839,7 @@ declare function loadConfigOrDefault(configPath: string): Config;
|
|
|
773
839
|
declare function updateModel(configPath: string, patch: {
|
|
774
840
|
model?: string;
|
|
775
841
|
}): ConfigView;
|
|
842
|
+
declare function updateSearch(configPath: string, patch: SearchConfigUpdate): ConfigView["search"];
|
|
776
843
|
declare function updateProvider(configPath: string, providerName: string, patch: ProviderConfigUpdate): ProviderConfigView | null;
|
|
777
844
|
declare function createCustomProvider(configPath: string, patch?: ProviderConfigUpdate): {
|
|
778
845
|
name: string;
|
|
@@ -781,15 +848,22 @@ declare function createCustomProvider(configPath: string, patch?: ProviderConfig
|
|
|
781
848
|
declare function deleteCustomProvider(configPath: string, providerName: string): boolean | null;
|
|
782
849
|
declare function testProviderConnection(configPath: string, providerName: string, patch: ProviderConnectionTestRequest): Promise<ProviderConnectionTestResult | null>;
|
|
783
850
|
declare function updateChannel(configPath: string, channelName: string, patch: Record<string, unknown>): Record<string, unknown> | null;
|
|
851
|
+
declare const DEFAULT_SESSION_TYPE = "native";
|
|
852
|
+
declare class SessionPatchValidationError extends Error {
|
|
853
|
+
readonly code: "SESSION_TYPE_INVALID" | "SESSION_TYPE_IMMUTABLE" | "SESSION_TYPE_UNAVAILABLE";
|
|
854
|
+
constructor(code: "SESSION_TYPE_INVALID" | "SESSION_TYPE_IMMUTABLE" | "SESSION_TYPE_UNAVAILABLE", message: string);
|
|
855
|
+
}
|
|
784
856
|
declare function listSessions(configPath: string, query?: {
|
|
785
857
|
q?: string;
|
|
786
858
|
limit?: number;
|
|
787
859
|
activeMinutes?: number;
|
|
788
860
|
}): SessionsListView;
|
|
789
861
|
declare function getSessionHistory(configPath: string, key: string, limit?: number): SessionHistoryView | null;
|
|
790
|
-
declare function patchSession(configPath: string, key: string, patch: SessionPatchUpdate
|
|
862
|
+
declare function patchSession(configPath: string, key: string, patch: SessionPatchUpdate, options?: {
|
|
863
|
+
availableSessionTypes?: string[];
|
|
864
|
+
}): SessionHistoryView | null;
|
|
791
865
|
declare function deleteSession(configPath: string, key: string): boolean;
|
|
792
866
|
declare function updateRuntime(configPath: string, patch: RuntimeConfigUpdate): Pick<ConfigView, "agents" | "bindings" | "session">;
|
|
793
867
|
declare function updateSecrets(configPath: string, patch: SecretsConfigUpdate): SecretsView;
|
|
794
868
|
|
|
795
|
-
export { type AgentBindingView, type AgentProfileView, type ApiError, type ApiResponse, type AppMetaView, type BindingPeerView, type ChannelSpecView, type ChatCapabilitiesView, type ChatCommandOptionView, type ChatCommandView, type ChatCommandsView, type ChatRunListView, type ChatRunState, type ChatRunView, type ChatTurnRequest, type ChatTurnResult, type ChatTurnStopRequest, type ChatTurnStopResult, type ChatTurnStreamEvent, type ChatTurnView, type ConfigActionExecuteRequest, type ConfigActionExecuteResult, type ConfigActionManifest, type ConfigActionType, type ConfigMetaView, type ConfigSchemaResponse, type ConfigUiHint, type ConfigUiHints, type ConfigView, type CronActionResult, type CronEnableRequest, type CronJobStateView, type CronJobView, type CronListView, type CronPayloadView, type CronRunRequest, type CronScheduleView, type MarketplaceApiConfig, type MarketplaceInstallKind, type MarketplaceInstallSkillParams, type MarketplaceInstallSpec, type MarketplaceInstalledRecord, type MarketplaceInstalledView, type MarketplaceInstaller, type MarketplaceItemSummary, type MarketplaceItemType, type MarketplaceItemView, type MarketplaceListView, type MarketplaceLocalizedTextMap, type MarketplacePluginContentView, type MarketplacePluginInstallKind, type MarketplacePluginInstallRequest, type MarketplacePluginInstallResult, type MarketplacePluginManageAction, type MarketplacePluginManageRequest, type MarketplacePluginManageResult, type MarketplaceRecommendationView, type MarketplaceSkillContentView, type MarketplaceSkillInstallKind, type MarketplaceSkillInstallRequest, type MarketplaceSkillInstallResult, type MarketplaceSkillManageAction, type MarketplaceSkillManageRequest, type MarketplaceSkillManageResult, type MarketplaceSort, type ProviderAuthImportResult, type ProviderAuthPollRequest, type ProviderAuthPollResult, type ProviderAuthStartRequest, type ProviderAuthStartResult, type ProviderConfigUpdate, type ProviderConfigView, type ProviderConnectionTestRequest, type ProviderConnectionTestResult, type ProviderCreateRequest, type ProviderCreateResult, type ProviderDeleteResult, type ProviderSpecView, type RuntimeConfigUpdate, type SecretProviderEnvView, type SecretProviderExecView, type SecretProviderFileView, type SecretProviderView, type SecretRefView, type SecretSourceView, type SecretsConfigUpdate, type SecretsView, type SessionConfigView, type SessionEntryView, type SessionEventView, type SessionHistoryView, type SessionMessageView, type SessionPatchUpdate, type SessionsListView, type UiChatRuntime, type UiServerEvent, type UiServerHandle, type UiServerOptions, buildConfigMeta, buildConfigSchemaView, buildConfigView, createCustomProvider, createUiRouter, deleteCustomProvider, deleteSession, executeConfigAction, getSessionHistory, listSessions, loadConfigOrDefault, patchSession, startUiServer, testProviderConnection, updateChannel, updateModel, updateProvider, updateRuntime, updateSecrets };
|
|
869
|
+
export { type AgentBindingView, type AgentProfileView, type ApiError, type ApiResponse, type AppMetaView, type BindingPeerView, type BochaFreshnessValue, type ChannelSpecView, type ChatCapabilitiesView, type ChatCommandOptionView, type ChatCommandView, type ChatCommandsView, type ChatRunListView, type ChatRunState, type ChatRunView, type ChatSessionTypeOptionView, type ChatSessionTypesView, type ChatTurnRequest, type ChatTurnResult, type ChatTurnStopRequest, type ChatTurnStopResult, type ChatTurnStreamEvent, type ChatTurnView, type ConfigActionExecuteRequest, type ConfigActionExecuteResult, type ConfigActionManifest, type ConfigActionType, type ConfigMetaView, type ConfigSchemaResponse, type ConfigUiHint, type ConfigUiHints, type ConfigView, type CronActionResult, type CronEnableRequest, type CronJobStateView, type CronJobView, type CronListView, type CronPayloadView, type CronRunRequest, type CronScheduleView, DEFAULT_SESSION_TYPE, type MarketplaceApiConfig, type MarketplaceInstallKind, type MarketplaceInstallSkillParams, type MarketplaceInstallSpec, type MarketplaceInstalledRecord, type MarketplaceInstalledView, type MarketplaceInstaller, type MarketplaceItemSummary, type MarketplaceItemType, type MarketplaceItemView, type MarketplaceListView, type MarketplaceLocalizedTextMap, type MarketplacePluginContentView, type MarketplacePluginInstallKind, type MarketplacePluginInstallRequest, type MarketplacePluginInstallResult, type MarketplacePluginManageAction, type MarketplacePluginManageRequest, type MarketplacePluginManageResult, type MarketplaceRecommendationView, type MarketplaceSkillContentView, type MarketplaceSkillInstallKind, type MarketplaceSkillInstallRequest, type MarketplaceSkillInstallResult, type MarketplaceSkillManageAction, type MarketplaceSkillManageRequest, type MarketplaceSkillManageResult, type MarketplaceSort, type ProviderAuthImportResult, type ProviderAuthPollRequest, type ProviderAuthPollResult, type ProviderAuthStartRequest, type ProviderAuthStartResult, type ProviderConfigUpdate, type ProviderConfigView, type ProviderConnectionTestRequest, type ProviderConnectionTestResult, type ProviderCreateRequest, type ProviderCreateResult, type ProviderDeleteResult, type ProviderSpecView, type RuntimeConfigUpdate, type SearchConfigUpdate, type SearchConfigView, type SearchProviderConfigView, type SearchProviderName, type SearchProviderSpecView, type SecretProviderEnvView, type SecretProviderExecView, type SecretProviderFileView, type SecretProviderView, type SecretRefView, type SecretSourceView, type SecretsConfigUpdate, type SecretsView, type SessionConfigView, type SessionEntryView, type SessionEventView, type SessionHistoryView, type SessionMessageView, type SessionPatchUpdate, SessionPatchValidationError, type SessionsListView, type UiChatRuntime, type UiServerEvent, type UiServerHandle, type UiServerOptions, buildConfigMeta, buildConfigSchemaView, buildConfigView, createCustomProvider, createUiRouter, deleteCustomProvider, deleteSession, executeConfigAction, getSessionHistory, listSessions, loadConfigOrDefault, patchSession, startUiServer, testProviderConnection, updateChannel, updateModel, updateProvider, updateRuntime, updateSearch, updateSecrets };
|
package/dist/index.js
CHANGED
|
@@ -212,6 +212,7 @@ function clearSecretRefsByPrefix(config, pathPrefix) {
|
|
|
212
212
|
}
|
|
213
213
|
}
|
|
214
214
|
var DOCS_BASE_URL = "https://docs.nextclaw.io";
|
|
215
|
+
var BOCHA_OPEN_URL = "https://open.bocha.cn";
|
|
215
216
|
var CHANNEL_TUTORIAL_URLS = {
|
|
216
217
|
feishu: {
|
|
217
218
|
default: `${DOCS_BASE_URL}/guide/tutorials/feishu`,
|
|
@@ -219,6 +220,22 @@ var CHANNEL_TUTORIAL_URLS = {
|
|
|
219
220
|
zh: `${DOCS_BASE_URL}/zh/guide/tutorials/feishu`
|
|
220
221
|
}
|
|
221
222
|
};
|
|
223
|
+
var SEARCH_PROVIDER_META = [
|
|
224
|
+
{
|
|
225
|
+
name: "bocha",
|
|
226
|
+
displayName: "Bocha Search",
|
|
227
|
+
description: "China-friendly web search with AI-ready summaries.",
|
|
228
|
+
docsUrl: BOCHA_OPEN_URL,
|
|
229
|
+
isDefault: true,
|
|
230
|
+
supportsSummary: true
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
name: "brave",
|
|
234
|
+
displayName: "Brave Search",
|
|
235
|
+
description: "Brave web search API kept as an optional provider.",
|
|
236
|
+
supportsSummary: false
|
|
237
|
+
}
|
|
238
|
+
];
|
|
222
239
|
function matchesExtraSensitivePath(path) {
|
|
223
240
|
if (path === "session" || path.startsWith("session.")) {
|
|
224
241
|
return false;
|
|
@@ -470,6 +487,7 @@ function buildConfigView(config) {
|
|
|
470
487
|
return {
|
|
471
488
|
agents: config.agents,
|
|
472
489
|
providers,
|
|
490
|
+
search: buildSearchView(config),
|
|
473
491
|
channels: sanitizePublicConfigValue(
|
|
474
492
|
config.channels,
|
|
475
493
|
"channels",
|
|
@@ -488,6 +506,40 @@ function buildConfigView(config) {
|
|
|
488
506
|
}
|
|
489
507
|
};
|
|
490
508
|
}
|
|
509
|
+
function toSearchProviderView(config, providerName, provider) {
|
|
510
|
+
const apiKeyPath = `search.providers.${providerName}.apiKey`;
|
|
511
|
+
const apiKeyRefSet = hasSecretRef(config, apiKeyPath);
|
|
512
|
+
const masked = maskApiKey(provider.apiKey);
|
|
513
|
+
const base = {
|
|
514
|
+
enabled: config.search.enabledProviders.includes(providerName),
|
|
515
|
+
apiKeySet: masked.apiKeySet || apiKeyRefSet,
|
|
516
|
+
apiKeyMasked: masked.apiKeyMasked ?? (apiKeyRefSet ? "****" : void 0),
|
|
517
|
+
baseUrl: provider.baseUrl
|
|
518
|
+
};
|
|
519
|
+
if ("docsUrl" in provider) {
|
|
520
|
+
base.docsUrl = provider.docsUrl;
|
|
521
|
+
}
|
|
522
|
+
if ("summary" in provider) {
|
|
523
|
+
base.summary = provider.summary;
|
|
524
|
+
}
|
|
525
|
+
if ("freshness" in provider) {
|
|
526
|
+
base.freshness = provider.freshness;
|
|
527
|
+
}
|
|
528
|
+
return base;
|
|
529
|
+
}
|
|
530
|
+
function buildSearchView(config) {
|
|
531
|
+
return {
|
|
532
|
+
provider: config.search.provider,
|
|
533
|
+
enabledProviders: [...config.search.enabledProviders],
|
|
534
|
+
defaults: {
|
|
535
|
+
maxResults: config.search.defaults.maxResults
|
|
536
|
+
},
|
|
537
|
+
providers: {
|
|
538
|
+
bocha: toSearchProviderView(config, "bocha", config.search.providers.bocha),
|
|
539
|
+
brave: toSearchProviderView(config, "brave", config.search.providers.brave)
|
|
540
|
+
}
|
|
541
|
+
};
|
|
542
|
+
}
|
|
491
543
|
function clearSecretRef(config, path) {
|
|
492
544
|
if (config.secrets.refs[path]) {
|
|
493
545
|
delete config.secrets.refs[path];
|
|
@@ -574,7 +626,7 @@ function buildConfigMeta(config) {
|
|
|
574
626
|
tutorialUrls
|
|
575
627
|
};
|
|
576
628
|
});
|
|
577
|
-
return { providers, channels };
|
|
629
|
+
return { providers, search: SEARCH_PROVIDER_META, channels };
|
|
578
630
|
}
|
|
579
631
|
function buildConfigSchemaView(_config) {
|
|
580
632
|
return buildConfigSchema({ version: getPackageVersion() });
|
|
@@ -643,6 +695,60 @@ function updateModel(configPath, patch) {
|
|
|
643
695
|
saveConfig(next, configPath);
|
|
644
696
|
return buildConfigView(next);
|
|
645
697
|
}
|
|
698
|
+
function updateSearch(configPath, patch) {
|
|
699
|
+
const config = loadConfigOrDefault(configPath);
|
|
700
|
+
if (patch.provider === "bocha" || patch.provider === "brave") {
|
|
701
|
+
config.search.provider = patch.provider;
|
|
702
|
+
}
|
|
703
|
+
if (Array.isArray(patch.enabledProviders)) {
|
|
704
|
+
config.search.enabledProviders = Array.from(new Set(
|
|
705
|
+
patch.enabledProviders.filter((value) => value === "bocha" || value === "brave")
|
|
706
|
+
));
|
|
707
|
+
}
|
|
708
|
+
if (patch.defaults && Object.prototype.hasOwnProperty.call(patch.defaults, "maxResults")) {
|
|
709
|
+
const nextMaxResults = patch.defaults.maxResults;
|
|
710
|
+
if (typeof nextMaxResults === "number" && Number.isFinite(nextMaxResults)) {
|
|
711
|
+
config.search.defaults.maxResults = Math.max(1, Math.min(50, Math.trunc(nextMaxResults)));
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
const bochaPatch = patch.providers?.bocha;
|
|
715
|
+
if (bochaPatch) {
|
|
716
|
+
if (Object.prototype.hasOwnProperty.call(bochaPatch, "apiKey")) {
|
|
717
|
+
config.search.providers.bocha.apiKey = bochaPatch.apiKey ?? "";
|
|
718
|
+
clearSecretRef(config, "search.providers.bocha.apiKey");
|
|
719
|
+
}
|
|
720
|
+
if (Object.prototype.hasOwnProperty.call(bochaPatch, "baseUrl")) {
|
|
721
|
+
config.search.providers.bocha.baseUrl = normalizeOptionalString(bochaPatch.baseUrl) ?? "https://api.bocha.cn/v1/web-search";
|
|
722
|
+
}
|
|
723
|
+
if (Object.prototype.hasOwnProperty.call(bochaPatch, "docsUrl")) {
|
|
724
|
+
config.search.providers.bocha.docsUrl = normalizeOptionalString(bochaPatch.docsUrl) ?? BOCHA_OPEN_URL;
|
|
725
|
+
}
|
|
726
|
+
if (Object.prototype.hasOwnProperty.call(bochaPatch, "summary")) {
|
|
727
|
+
config.search.providers.bocha.summary = Boolean(bochaPatch.summary);
|
|
728
|
+
}
|
|
729
|
+
if (Object.prototype.hasOwnProperty.call(bochaPatch, "freshness")) {
|
|
730
|
+
const freshness = normalizeOptionalString(bochaPatch.freshness);
|
|
731
|
+
if (freshness === "noLimit" || freshness === "oneDay" || freshness === "oneWeek" || freshness === "oneMonth" || freshness === "oneYear") {
|
|
732
|
+
config.search.providers.bocha.freshness = freshness;
|
|
733
|
+
} else {
|
|
734
|
+
config.search.providers.bocha.freshness = "noLimit";
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
const bravePatch = patch.providers?.brave;
|
|
739
|
+
if (bravePatch) {
|
|
740
|
+
if (Object.prototype.hasOwnProperty.call(bravePatch, "apiKey")) {
|
|
741
|
+
config.search.providers.brave.apiKey = bravePatch.apiKey ?? "";
|
|
742
|
+
clearSecretRef(config, "search.providers.brave.apiKey");
|
|
743
|
+
}
|
|
744
|
+
if (Object.prototype.hasOwnProperty.call(bravePatch, "baseUrl")) {
|
|
745
|
+
config.search.providers.brave.baseUrl = normalizeOptionalString(bravePatch.baseUrl) ?? "https://api.search.brave.com/res/v1/web/search";
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
const next = ConfigSchema.parse(config);
|
|
749
|
+
saveConfig(next, configPath);
|
|
750
|
+
return buildSearchView(next);
|
|
751
|
+
}
|
|
646
752
|
function updateProvider(configPath, providerName, patch) {
|
|
647
753
|
const config = loadConfigOrDefault(configPath);
|
|
648
754
|
const provider = ensureProviderConfig(config, providerName);
|
|
@@ -875,6 +981,36 @@ function normalizeSessionKey(value) {
|
|
|
875
981
|
function createSessionManager(config) {
|
|
876
982
|
return new SessionManager(getWorkspacePathFromConfig(config));
|
|
877
983
|
}
|
|
984
|
+
var DEFAULT_SESSION_TYPE = "native";
|
|
985
|
+
var SESSION_TYPE_METADATA_KEY = "session_type";
|
|
986
|
+
function normalizeSessionType(value) {
|
|
987
|
+
if (typeof value !== "string") {
|
|
988
|
+
return null;
|
|
989
|
+
}
|
|
990
|
+
const normalized = value.trim().toLowerCase();
|
|
991
|
+
return normalized.length > 0 ? normalized : null;
|
|
992
|
+
}
|
|
993
|
+
function readSessionType(session) {
|
|
994
|
+
const normalized = normalizeSessionType(session.metadata[SESSION_TYPE_METADATA_KEY]);
|
|
995
|
+
return normalized ?? DEFAULT_SESSION_TYPE;
|
|
996
|
+
}
|
|
997
|
+
function countUserMessages(session) {
|
|
998
|
+
return session.messages.reduce((total, message) => {
|
|
999
|
+
const role = typeof message.role === "string" ? message.role.trim().toLowerCase() : "";
|
|
1000
|
+
return role === "user" ? total + 1 : total;
|
|
1001
|
+
}, 0);
|
|
1002
|
+
}
|
|
1003
|
+
function isSessionTypeMutable(session) {
|
|
1004
|
+
const activeUiRunId = typeof session.metadata.ui_active_run_id === "string" ? session.metadata.ui_active_run_id.trim() : "";
|
|
1005
|
+
return countUserMessages(session) === 0 && activeUiRunId.length === 0;
|
|
1006
|
+
}
|
|
1007
|
+
var SessionPatchValidationError = class extends Error {
|
|
1008
|
+
constructor(code, message) {
|
|
1009
|
+
super(message);
|
|
1010
|
+
this.code = code;
|
|
1011
|
+
this.name = "SessionPatchValidationError";
|
|
1012
|
+
}
|
|
1013
|
+
};
|
|
878
1014
|
function listSessions(configPath, query) {
|
|
879
1015
|
const config = loadConfigOrDefault(configPath);
|
|
880
1016
|
const sessionManager = createSessionManager(config);
|
|
@@ -895,12 +1031,22 @@ function listSessions(configPath, query) {
|
|
|
895
1031
|
const preferredModel = typeof metadata.preferred_model === "string" ? metadata.preferred_model.trim() : "";
|
|
896
1032
|
const createdAt = typeof item.created_at === "string" ? item.created_at : (/* @__PURE__ */ new Date(0)).toISOString();
|
|
897
1033
|
const updatedAt = typeof item.updated_at === "string" ? item.updated_at : createdAt;
|
|
1034
|
+
const sessionType = readSessionType({
|
|
1035
|
+
metadata,
|
|
1036
|
+
messages
|
|
1037
|
+
});
|
|
1038
|
+
const sessionTypeMutable = isSessionTypeMutable({
|
|
1039
|
+
metadata,
|
|
1040
|
+
messages
|
|
1041
|
+
});
|
|
898
1042
|
return {
|
|
899
1043
|
key,
|
|
900
1044
|
createdAt,
|
|
901
1045
|
updatedAt,
|
|
902
1046
|
label: label || void 0,
|
|
903
1047
|
preferredModel: preferredModel || void 0,
|
|
1048
|
+
sessionType,
|
|
1049
|
+
sessionTypeMutable,
|
|
904
1050
|
messageCount: messages.length,
|
|
905
1051
|
lastRole: typeof lastMessage?.role === "string" ? lastMessage.role : void 0,
|
|
906
1052
|
lastTimestamp: typeof lastMessage?.timestamp === "string" ? lastMessage.timestamp : void 0
|
|
@@ -940,10 +1086,14 @@ function getSessionHistory(configPath, key, limit) {
|
|
|
940
1086
|
const safeEventLimit = Math.min(2e3, Math.max(50, safeLimit * 4));
|
|
941
1087
|
const allEvents = session.events ?? [];
|
|
942
1088
|
const events = allEvents.length > safeEventLimit ? allEvents.slice(-safeEventLimit) : allEvents;
|
|
1089
|
+
const sessionType = readSessionType(session);
|
|
1090
|
+
const sessionTypeMutable = isSessionTypeMutable(session);
|
|
943
1091
|
return {
|
|
944
1092
|
key: normalizedKey,
|
|
945
1093
|
totalMessages: allMessages.length,
|
|
946
1094
|
totalEvents: allEvents.length,
|
|
1095
|
+
sessionType,
|
|
1096
|
+
sessionTypeMutable,
|
|
947
1097
|
metadata: session.metadata,
|
|
948
1098
|
messages: messages.map((message) => {
|
|
949
1099
|
const entry = {
|
|
@@ -990,7 +1140,7 @@ function getSessionHistory(configPath, key, limit) {
|
|
|
990
1140
|
})
|
|
991
1141
|
};
|
|
992
1142
|
}
|
|
993
|
-
function patchSession(configPath, key, patch) {
|
|
1143
|
+
function patchSession(configPath, key, patch, options) {
|
|
994
1144
|
const normalizedKey = normalizeSessionKey(key);
|
|
995
1145
|
if (!normalizedKey) {
|
|
996
1146
|
return null;
|
|
@@ -1020,6 +1170,32 @@ function patchSession(configPath, key, patch) {
|
|
|
1020
1170
|
delete session.metadata.preferred_model;
|
|
1021
1171
|
}
|
|
1022
1172
|
}
|
|
1173
|
+
if (Object.prototype.hasOwnProperty.call(patch, "sessionType")) {
|
|
1174
|
+
const normalizedSessionType = normalizeSessionType(patch.sessionType);
|
|
1175
|
+
if (!normalizedSessionType) {
|
|
1176
|
+
throw new SessionPatchValidationError(
|
|
1177
|
+
"SESSION_TYPE_INVALID",
|
|
1178
|
+
"sessionType must be a non-empty string"
|
|
1179
|
+
);
|
|
1180
|
+
}
|
|
1181
|
+
if (!isSessionTypeMutable(session)) {
|
|
1182
|
+
throw new SessionPatchValidationError(
|
|
1183
|
+
"SESSION_TYPE_IMMUTABLE",
|
|
1184
|
+
"sessionType cannot be changed after the first user message"
|
|
1185
|
+
);
|
|
1186
|
+
}
|
|
1187
|
+
const availableSessionTypes = new Set(
|
|
1188
|
+
(options?.availableSessionTypes ?? [DEFAULT_SESSION_TYPE]).map((item) => normalizeSessionType(item)).filter((item) => Boolean(item))
|
|
1189
|
+
);
|
|
1190
|
+
availableSessionTypes.add(DEFAULT_SESSION_TYPE);
|
|
1191
|
+
if (!availableSessionTypes.has(normalizedSessionType)) {
|
|
1192
|
+
throw new SessionPatchValidationError(
|
|
1193
|
+
"SESSION_TYPE_UNAVAILABLE",
|
|
1194
|
+
`sessionType is unavailable: ${normalizedSessionType}`
|
|
1195
|
+
);
|
|
1196
|
+
}
|
|
1197
|
+
session.metadata[SESSION_TYPE_METADATA_KEY] = normalizedSessionType;
|
|
1198
|
+
}
|
|
1023
1199
|
session.updatedAt = /* @__PURE__ */ new Date();
|
|
1024
1200
|
sessionManager.save(session);
|
|
1025
1201
|
return getSessionHistory(configPath, normalizedKey, 200);
|
|
@@ -1851,6 +2027,67 @@ function readNonEmptyString(value) {
|
|
|
1851
2027
|
const trimmed = value.trim();
|
|
1852
2028
|
return trimmed || void 0;
|
|
1853
2029
|
}
|
|
2030
|
+
function normalizeSessionType2(value) {
|
|
2031
|
+
return readNonEmptyString(value)?.toLowerCase();
|
|
2032
|
+
}
|
|
2033
|
+
function resolveSessionTypeLabel(sessionType) {
|
|
2034
|
+
if (sessionType === "native") {
|
|
2035
|
+
return "Native";
|
|
2036
|
+
}
|
|
2037
|
+
if (sessionType === "codex-sdk") {
|
|
2038
|
+
return "Codex";
|
|
2039
|
+
}
|
|
2040
|
+
if (sessionType === "claude-agent-sdk") {
|
|
2041
|
+
return "Claude Code";
|
|
2042
|
+
}
|
|
2043
|
+
return sessionType;
|
|
2044
|
+
}
|
|
2045
|
+
async function buildChatSessionTypesView(chatRuntime) {
|
|
2046
|
+
if (!chatRuntime?.listSessionTypes) {
|
|
2047
|
+
return {
|
|
2048
|
+
defaultType: DEFAULT_SESSION_TYPE,
|
|
2049
|
+
options: [{ value: DEFAULT_SESSION_TYPE, label: resolveSessionTypeLabel(DEFAULT_SESSION_TYPE) }]
|
|
2050
|
+
};
|
|
2051
|
+
}
|
|
2052
|
+
const payload = await chatRuntime.listSessionTypes();
|
|
2053
|
+
const deduped = /* @__PURE__ */ new Map();
|
|
2054
|
+
for (const rawOption of payload.options ?? []) {
|
|
2055
|
+
const normalized = normalizeSessionType2(rawOption.value);
|
|
2056
|
+
if (!normalized) {
|
|
2057
|
+
continue;
|
|
2058
|
+
}
|
|
2059
|
+
deduped.set(normalized, {
|
|
2060
|
+
value: normalized,
|
|
2061
|
+
label: readNonEmptyString(rawOption.label) ?? resolveSessionTypeLabel(normalized)
|
|
2062
|
+
});
|
|
2063
|
+
}
|
|
2064
|
+
if (!deduped.has(DEFAULT_SESSION_TYPE)) {
|
|
2065
|
+
deduped.set(DEFAULT_SESSION_TYPE, {
|
|
2066
|
+
value: DEFAULT_SESSION_TYPE,
|
|
2067
|
+
label: resolveSessionTypeLabel(DEFAULT_SESSION_TYPE)
|
|
2068
|
+
});
|
|
2069
|
+
}
|
|
2070
|
+
const defaultType = normalizeSessionType2(payload.defaultType) ?? DEFAULT_SESSION_TYPE;
|
|
2071
|
+
if (!deduped.has(defaultType)) {
|
|
2072
|
+
deduped.set(defaultType, {
|
|
2073
|
+
value: defaultType,
|
|
2074
|
+
label: resolveSessionTypeLabel(defaultType)
|
|
2075
|
+
});
|
|
2076
|
+
}
|
|
2077
|
+
const options = Array.from(deduped.values()).sort((left, right) => {
|
|
2078
|
+
if (left.value === DEFAULT_SESSION_TYPE) {
|
|
2079
|
+
return -1;
|
|
2080
|
+
}
|
|
2081
|
+
if (right.value === DEFAULT_SESSION_TYPE) {
|
|
2082
|
+
return 1;
|
|
2083
|
+
}
|
|
2084
|
+
return left.value.localeCompare(right.value);
|
|
2085
|
+
});
|
|
2086
|
+
return {
|
|
2087
|
+
defaultType,
|
|
2088
|
+
options
|
|
2089
|
+
};
|
|
2090
|
+
}
|
|
1854
2091
|
function resolveAgentIdFromSessionKey(sessionKey) {
|
|
1855
2092
|
const parsed = NextclawCore.parseAgentScopedSessionKey(sessionKey);
|
|
1856
2093
|
const agentId = readNonEmptyString(parsed?.agentId);
|
|
@@ -2895,6 +3132,15 @@ function createUiRouter(options) {
|
|
|
2895
3132
|
model: view.agents.defaults.model
|
|
2896
3133
|
}));
|
|
2897
3134
|
});
|
|
3135
|
+
app.put("/api/config/search", async (c) => {
|
|
3136
|
+
const body = await readJson(c.req.raw);
|
|
3137
|
+
if (!body.ok) {
|
|
3138
|
+
return c.json(err("INVALID_BODY", "invalid json body"), 400);
|
|
3139
|
+
}
|
|
3140
|
+
const result = updateSearch(options.configPath, body.data);
|
|
3141
|
+
options.publish({ type: "config.updated", payload: { path: "search" } });
|
|
3142
|
+
return c.json(ok(result));
|
|
3143
|
+
});
|
|
2898
3144
|
app.put("/api/config/providers/:provider", async (c) => {
|
|
2899
3145
|
const provider = c.req.param("provider");
|
|
2900
3146
|
const body = await readJson(c.req.raw);
|
|
@@ -3052,6 +3298,14 @@ function createUiRouter(options) {
|
|
|
3052
3298
|
return c.json(err("CHAT_RUNTIME_FAILED", String(error)), 500);
|
|
3053
3299
|
}
|
|
3054
3300
|
});
|
|
3301
|
+
app.get("/api/chat/session-types", async (c) => {
|
|
3302
|
+
try {
|
|
3303
|
+
const payload = await buildChatSessionTypesView(options.chatRuntime);
|
|
3304
|
+
return c.json(ok(payload));
|
|
3305
|
+
} catch (error) {
|
|
3306
|
+
return c.json(err("CHAT_SESSION_TYPES_FAILED", String(error)), 500);
|
|
3307
|
+
}
|
|
3308
|
+
});
|
|
3055
3309
|
app.get("/api/chat/commands", async (c) => {
|
|
3056
3310
|
try {
|
|
3057
3311
|
const config = loadConfigOrDefault(options.configPath);
|
|
@@ -3524,7 +3778,25 @@ function createUiRouter(options) {
|
|
|
3524
3778
|
if (!body.ok || !body.data || typeof body.data !== "object") {
|
|
3525
3779
|
return c.json(err("INVALID_BODY", "invalid json body"), 400);
|
|
3526
3780
|
}
|
|
3527
|
-
|
|
3781
|
+
let availableSessionTypes;
|
|
3782
|
+
if (Object.prototype.hasOwnProperty.call(body.data, "sessionType")) {
|
|
3783
|
+
const sessionTypes = await buildChatSessionTypesView(options.chatRuntime);
|
|
3784
|
+
availableSessionTypes = sessionTypes.options.map((item) => item.value);
|
|
3785
|
+
}
|
|
3786
|
+
let data;
|
|
3787
|
+
try {
|
|
3788
|
+
data = patchSession(options.configPath, key, body.data, {
|
|
3789
|
+
...availableSessionTypes ? { availableSessionTypes } : {}
|
|
3790
|
+
});
|
|
3791
|
+
} catch (error) {
|
|
3792
|
+
if (error instanceof SessionPatchValidationError) {
|
|
3793
|
+
if (error.code === "SESSION_TYPE_IMMUTABLE") {
|
|
3794
|
+
return c.json(err(error.code, error.message), 409);
|
|
3795
|
+
}
|
|
3796
|
+
return c.json(err(error.code, error.message), 400);
|
|
3797
|
+
}
|
|
3798
|
+
throw error;
|
|
3799
|
+
}
|
|
3528
3800
|
if (!data) {
|
|
3529
3801
|
return c.json(err("NOT_FOUND", `session not found: ${key}`), 404);
|
|
3530
3802
|
}
|
|
@@ -3729,6 +4001,8 @@ function startUiServer(options) {
|
|
|
3729
4001
|
};
|
|
3730
4002
|
}
|
|
3731
4003
|
export {
|
|
4004
|
+
DEFAULT_SESSION_TYPE,
|
|
4005
|
+
SessionPatchValidationError,
|
|
3732
4006
|
buildConfigMeta,
|
|
3733
4007
|
buildConfigSchemaView,
|
|
3734
4008
|
buildConfigView,
|
|
@@ -3747,5 +4021,6 @@ export {
|
|
|
3747
4021
|
updateModel,
|
|
3748
4022
|
updateProvider,
|
|
3749
4023
|
updateRuntime,
|
|
4024
|
+
updateSearch,
|
|
3750
4025
|
updateSecrets
|
|
3751
4026
|
};
|
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nextclaw/server",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.9",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Nextclaw UI/API server.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"exports": {
|
|
8
8
|
".": {
|
|
9
|
+
"development": "./src/index.ts",
|
|
9
10
|
"types": "./dist/index.d.ts",
|
|
10
11
|
"default": "./dist/index.js"
|
|
11
12
|
}
|
|
@@ -17,9 +18,9 @@
|
|
|
17
18
|
"@hono/node-server": "^1.13.3",
|
|
18
19
|
"hono": "^4.6.2",
|
|
19
20
|
"ws": "^8.18.0",
|
|
20
|
-
"@nextclaw/openclaw-compat": "0.2.
|
|
21
|
-
"@nextclaw/
|
|
22
|
-
"@nextclaw/
|
|
21
|
+
"@nextclaw/openclaw-compat": "0.2.4",
|
|
22
|
+
"@nextclaw/core": "0.7.5",
|
|
23
|
+
"@nextclaw/runtime": "0.1.4"
|
|
23
24
|
},
|
|
24
25
|
"devDependencies": {
|
|
25
26
|
"@types/node": "^20.17.6",
|