@nextclaw/server 0.5.18 → 0.5.20
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 +23 -1
- package/dist/index.js +171 -10
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -77,11 +77,19 @@ type SessionMessageView = {
|
|
|
77
77
|
tool_calls?: Array<Record<string, unknown>>;
|
|
78
78
|
reasoning_content?: string;
|
|
79
79
|
};
|
|
80
|
+
type SessionEventView = {
|
|
81
|
+
seq: number;
|
|
82
|
+
type: string;
|
|
83
|
+
timestamp: string;
|
|
84
|
+
message?: SessionMessageView;
|
|
85
|
+
};
|
|
80
86
|
type SessionHistoryView = {
|
|
81
87
|
key: string;
|
|
82
88
|
totalMessages: number;
|
|
89
|
+
totalEvents: number;
|
|
83
90
|
metadata: Record<string, unknown>;
|
|
84
91
|
messages: SessionMessageView[];
|
|
92
|
+
events: SessionEventView[];
|
|
85
93
|
};
|
|
86
94
|
type SessionPatchUpdate = {
|
|
87
95
|
label?: string | null;
|
|
@@ -206,6 +214,19 @@ type ChatTurnResult = {
|
|
|
206
214
|
model?: string;
|
|
207
215
|
metadata?: Record<string, unknown>;
|
|
208
216
|
};
|
|
217
|
+
type ChatTurnStreamEvent = {
|
|
218
|
+
type: "delta";
|
|
219
|
+
delta: string;
|
|
220
|
+
} | {
|
|
221
|
+
type: "session_event";
|
|
222
|
+
event: SessionEventView;
|
|
223
|
+
} | {
|
|
224
|
+
type: "final";
|
|
225
|
+
result: ChatTurnResult;
|
|
226
|
+
} | {
|
|
227
|
+
type: "error";
|
|
228
|
+
error: string;
|
|
229
|
+
};
|
|
209
230
|
type ChatTurnView = {
|
|
210
231
|
reply: string;
|
|
211
232
|
sessionKey: string;
|
|
@@ -217,6 +238,7 @@ type ChatTurnView = {
|
|
|
217
238
|
};
|
|
218
239
|
type UiChatRuntime = {
|
|
219
240
|
processTurn: (params: ChatTurnRequest) => Promise<ChatTurnResult>;
|
|
241
|
+
processTurnStream?: (params: ChatTurnRequest) => AsyncGenerator<ChatTurnStreamEvent>;
|
|
220
242
|
};
|
|
221
243
|
type ConfigView = {
|
|
222
244
|
agents: {
|
|
@@ -568,4 +590,4 @@ declare function deleteSession(configPath: string, key: string): boolean;
|
|
|
568
590
|
declare function updateRuntime(configPath: string, patch: RuntimeConfigUpdate): Pick<ConfigView, "agents" | "bindings" | "session">;
|
|
569
591
|
declare function updateSecrets(configPath: string, patch: SecretsConfigUpdate): SecretsView;
|
|
570
592
|
|
|
571
|
-
export { type AgentBindingView, type AgentProfileView, type ApiError, type ApiResponse, type BindingPeerView, type ChannelSpecView, type ChatTurnRequest, type ChatTurnResult, 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 MarketplacePluginInstallRequest, type MarketplacePluginInstallResult, type MarketplacePluginManageAction, type MarketplacePluginManageRequest, type MarketplacePluginManageResult, type MarketplaceRecommendationView, type MarketplaceSkillInstallRequest, type MarketplaceSkillInstallResult, type MarketplaceSkillManageAction, type MarketplaceSkillManageRequest, type MarketplaceSkillManageResult, type MarketplaceSort, type ProviderConfigUpdate, type ProviderConfigView, 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 SessionHistoryView, type SessionMessageView, type SessionPatchUpdate, type SessionsListView, type UiChatRuntime, type UiServerEvent, type UiServerHandle, type UiServerOptions, buildConfigMeta, buildConfigSchemaView, buildConfigView, createUiRouter, deleteSession, executeConfigAction, getSessionHistory, listSessions, loadConfigOrDefault, patchSession, startUiServer, updateChannel, updateModel, updateProvider, updateRuntime, updateSecrets };
|
|
593
|
+
export { type AgentBindingView, type AgentProfileView, type ApiError, type ApiResponse, type BindingPeerView, type ChannelSpecView, type ChatTurnRequest, type ChatTurnResult, 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 MarketplacePluginInstallRequest, type MarketplacePluginInstallResult, type MarketplacePluginManageAction, type MarketplacePluginManageRequest, type MarketplacePluginManageResult, type MarketplaceRecommendationView, type MarketplaceSkillInstallRequest, type MarketplaceSkillInstallResult, type MarketplaceSkillManageAction, type MarketplaceSkillManageRequest, type MarketplaceSkillManageResult, type MarketplaceSort, type ProviderConfigUpdate, type ProviderConfigView, 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, createUiRouter, deleteSession, executeConfigAction, getSessionHistory, listSessions, loadConfigOrDefault, patchSession, startUiServer, updateChannel, updateModel, updateProvider, updateRuntime, updateSecrets };
|
package/dist/index.js
CHANGED
|
@@ -490,9 +490,13 @@ function getSessionHistory(configPath, key, limit) {
|
|
|
490
490
|
const safeLimit = typeof limit === "number" ? Math.min(500, Math.max(1, Math.trunc(limit))) : 200;
|
|
491
491
|
const allMessages = session.messages;
|
|
492
492
|
const messages = allMessages.length > safeLimit ? allMessages.slice(-safeLimit) : allMessages;
|
|
493
|
+
const safeEventLimit = Math.min(2e3, Math.max(50, safeLimit * 4));
|
|
494
|
+
const allEvents = session.events ?? [];
|
|
495
|
+
const events = allEvents.length > safeEventLimit ? allEvents.slice(-safeEventLimit) : allEvents;
|
|
493
496
|
return {
|
|
494
497
|
key: normalizedKey,
|
|
495
498
|
totalMessages: allMessages.length,
|
|
499
|
+
totalEvents: allEvents.length,
|
|
496
500
|
metadata: session.metadata,
|
|
497
501
|
messages: messages.map((message) => {
|
|
498
502
|
const entry = {
|
|
@@ -513,6 +517,29 @@ function getSessionHistory(configPath, key, limit) {
|
|
|
513
517
|
entry.reasoning_content = message.reasoning_content;
|
|
514
518
|
}
|
|
515
519
|
return entry;
|
|
520
|
+
}),
|
|
521
|
+
events: events.map((event) => {
|
|
522
|
+
const entry = {
|
|
523
|
+
seq: event.seq,
|
|
524
|
+
type: event.type,
|
|
525
|
+
timestamp: event.timestamp
|
|
526
|
+
};
|
|
527
|
+
const message = event.data?.message;
|
|
528
|
+
if (message && typeof message === "object" && !Array.isArray(message)) {
|
|
529
|
+
const typed = message;
|
|
530
|
+
if (typeof typed.role === "string" && typeof typed.timestamp === "string") {
|
|
531
|
+
entry.message = {
|
|
532
|
+
role: typed.role,
|
|
533
|
+
content: typed.content,
|
|
534
|
+
timestamp: typed.timestamp,
|
|
535
|
+
...typeof typed.name === "string" ? { name: typed.name } : {},
|
|
536
|
+
...typeof typed.tool_call_id === "string" ? { tool_call_id: typed.tool_call_id } : {},
|
|
537
|
+
...Array.isArray(typed.tool_calls) ? { tool_calls: typed.tool_calls } : {},
|
|
538
|
+
...typeof typed.reasoning_content === "string" ? { reasoning_content: typed.reasoning_content } : {}
|
|
539
|
+
};
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
return entry;
|
|
516
543
|
})
|
|
517
544
|
};
|
|
518
545
|
}
|
|
@@ -819,6 +846,24 @@ function resolveAgentIdFromSessionKey(sessionKey) {
|
|
|
819
846
|
const agentId = readNonEmptyString(parsed?.agentId);
|
|
820
847
|
return agentId;
|
|
821
848
|
}
|
|
849
|
+
function buildChatTurnView(params) {
|
|
850
|
+
const completedAt = /* @__PURE__ */ new Date();
|
|
851
|
+
return {
|
|
852
|
+
reply: String(params.result.reply ?? ""),
|
|
853
|
+
sessionKey: readNonEmptyString(params.result.sessionKey) ?? params.fallbackSessionKey,
|
|
854
|
+
...readNonEmptyString(params.result.agentId) || params.requestedAgentId ? { agentId: readNonEmptyString(params.result.agentId) ?? params.requestedAgentId } : {},
|
|
855
|
+
...readNonEmptyString(params.result.model) || params.requestedModel ? { model: readNonEmptyString(params.result.model) ?? params.requestedModel } : {},
|
|
856
|
+
requestedAt: params.requestedAt.toISOString(),
|
|
857
|
+
completedAt: completedAt.toISOString(),
|
|
858
|
+
durationMs: Math.max(0, completedAt.getTime() - params.startedAtMs)
|
|
859
|
+
};
|
|
860
|
+
}
|
|
861
|
+
function toSseFrame(event, data) {
|
|
862
|
+
return `event: ${event}
|
|
863
|
+
data: ${JSON.stringify(data)}
|
|
864
|
+
|
|
865
|
+
`;
|
|
866
|
+
}
|
|
822
867
|
function normalizeMarketplaceBaseUrl(options) {
|
|
823
868
|
const fromOptions = options.marketplace?.apiBaseUrl?.trim();
|
|
824
869
|
const fromEnv = process.env.NEXTCLAW_MARKETPLACE_API_BASE?.trim();
|
|
@@ -1600,22 +1645,138 @@ function createUiRouter(options) {
|
|
|
1600
1645
|
};
|
|
1601
1646
|
try {
|
|
1602
1647
|
const result = await options.chatRuntime.processTurn(request);
|
|
1603
|
-
const
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
durationMs: Math.max(0, completedAt.getTime() - startedAtMs)
|
|
1612
|
-
};
|
|
1648
|
+
const response = buildChatTurnView({
|
|
1649
|
+
result,
|
|
1650
|
+
fallbackSessionKey: sessionKey,
|
|
1651
|
+
requestedAgentId,
|
|
1652
|
+
requestedModel,
|
|
1653
|
+
requestedAt,
|
|
1654
|
+
startedAtMs
|
|
1655
|
+
});
|
|
1613
1656
|
options.publish({ type: "config.updated", payload: { path: "session" } });
|
|
1614
1657
|
return c.json(ok(response));
|
|
1615
1658
|
} catch (error) {
|
|
1616
1659
|
return c.json(err("CHAT_TURN_FAILED", String(error)), 500);
|
|
1617
1660
|
}
|
|
1618
1661
|
});
|
|
1662
|
+
app.post("/api/chat/turn/stream", async (c) => {
|
|
1663
|
+
const chatRuntime = options.chatRuntime;
|
|
1664
|
+
if (!chatRuntime) {
|
|
1665
|
+
return c.json(err("NOT_AVAILABLE", "chat runtime unavailable"), 503);
|
|
1666
|
+
}
|
|
1667
|
+
const body = await readJson(c.req.raw);
|
|
1668
|
+
if (!body.ok) {
|
|
1669
|
+
return c.json(err("INVALID_BODY", "invalid json body"), 400);
|
|
1670
|
+
}
|
|
1671
|
+
const message = readNonEmptyString(body.data.message);
|
|
1672
|
+
if (!message) {
|
|
1673
|
+
return c.json(err("INVALID_BODY", "message is required"), 400);
|
|
1674
|
+
}
|
|
1675
|
+
const sessionKey = readNonEmptyString(body.data.sessionKey) ?? `ui:${Date.now().toString(36)}:${Math.random().toString(36).slice(2, 8)}`;
|
|
1676
|
+
const requestedAt = /* @__PURE__ */ new Date();
|
|
1677
|
+
const startedAtMs = requestedAt.getTime();
|
|
1678
|
+
const metadata = isRecord(body.data.metadata) ? body.data.metadata : void 0;
|
|
1679
|
+
const requestedAgentId = readNonEmptyString(body.data.agentId) ?? resolveAgentIdFromSessionKey(sessionKey);
|
|
1680
|
+
const requestedModel = readNonEmptyString(body.data.model);
|
|
1681
|
+
const request = {
|
|
1682
|
+
message,
|
|
1683
|
+
sessionKey,
|
|
1684
|
+
channel: readNonEmptyString(body.data.channel) ?? "ui",
|
|
1685
|
+
chatId: readNonEmptyString(body.data.chatId) ?? "web-ui",
|
|
1686
|
+
...requestedAgentId ? { agentId: requestedAgentId } : {},
|
|
1687
|
+
...requestedModel ? { model: requestedModel } : {},
|
|
1688
|
+
...metadata ? { metadata } : {}
|
|
1689
|
+
};
|
|
1690
|
+
const encoder = new TextEncoder();
|
|
1691
|
+
const stream = new ReadableStream({
|
|
1692
|
+
start: async (controller) => {
|
|
1693
|
+
const push = (event, data) => {
|
|
1694
|
+
controller.enqueue(encoder.encode(toSseFrame(event, data)));
|
|
1695
|
+
};
|
|
1696
|
+
try {
|
|
1697
|
+
push("ready", {
|
|
1698
|
+
sessionKey,
|
|
1699
|
+
requestedAt: requestedAt.toISOString()
|
|
1700
|
+
});
|
|
1701
|
+
const streamTurn = chatRuntime.processTurnStream;
|
|
1702
|
+
if (!streamTurn) {
|
|
1703
|
+
const result = await chatRuntime.processTurn(request);
|
|
1704
|
+
const response = buildChatTurnView({
|
|
1705
|
+
result,
|
|
1706
|
+
fallbackSessionKey: sessionKey,
|
|
1707
|
+
requestedAgentId,
|
|
1708
|
+
requestedModel,
|
|
1709
|
+
requestedAt,
|
|
1710
|
+
startedAtMs
|
|
1711
|
+
});
|
|
1712
|
+
push("final", response);
|
|
1713
|
+
options.publish({ type: "config.updated", payload: { path: "session" } });
|
|
1714
|
+
push("done", { ok: true });
|
|
1715
|
+
return;
|
|
1716
|
+
}
|
|
1717
|
+
let hasFinal = false;
|
|
1718
|
+
for await (const event of streamTurn(request)) {
|
|
1719
|
+
const typed = event;
|
|
1720
|
+
if (typed.type === "delta") {
|
|
1721
|
+
if (typed.delta) {
|
|
1722
|
+
push("delta", { delta: typed.delta });
|
|
1723
|
+
}
|
|
1724
|
+
continue;
|
|
1725
|
+
}
|
|
1726
|
+
if (typed.type === "session_event") {
|
|
1727
|
+
push("session_event", typed.event);
|
|
1728
|
+
continue;
|
|
1729
|
+
}
|
|
1730
|
+
if (typed.type === "final") {
|
|
1731
|
+
const response = buildChatTurnView({
|
|
1732
|
+
result: typed.result,
|
|
1733
|
+
fallbackSessionKey: sessionKey,
|
|
1734
|
+
requestedAgentId,
|
|
1735
|
+
requestedModel,
|
|
1736
|
+
requestedAt,
|
|
1737
|
+
startedAtMs
|
|
1738
|
+
});
|
|
1739
|
+
hasFinal = true;
|
|
1740
|
+
push("final", response);
|
|
1741
|
+
options.publish({ type: "config.updated", payload: { path: "session" } });
|
|
1742
|
+
continue;
|
|
1743
|
+
}
|
|
1744
|
+
if (typed.type === "error") {
|
|
1745
|
+
push("error", {
|
|
1746
|
+
code: "CHAT_TURN_FAILED",
|
|
1747
|
+
message: typed.error
|
|
1748
|
+
});
|
|
1749
|
+
return;
|
|
1750
|
+
}
|
|
1751
|
+
}
|
|
1752
|
+
if (!hasFinal) {
|
|
1753
|
+
push("error", {
|
|
1754
|
+
code: "CHAT_TURN_FAILED",
|
|
1755
|
+
message: "stream ended without a final result"
|
|
1756
|
+
});
|
|
1757
|
+
return;
|
|
1758
|
+
}
|
|
1759
|
+
push("done", { ok: true });
|
|
1760
|
+
} catch (error) {
|
|
1761
|
+
push("error", {
|
|
1762
|
+
code: "CHAT_TURN_FAILED",
|
|
1763
|
+
message: String(error)
|
|
1764
|
+
});
|
|
1765
|
+
} finally {
|
|
1766
|
+
controller.close();
|
|
1767
|
+
}
|
|
1768
|
+
}
|
|
1769
|
+
});
|
|
1770
|
+
return new Response(stream, {
|
|
1771
|
+
status: 200,
|
|
1772
|
+
headers: {
|
|
1773
|
+
"Content-Type": "text/event-stream; charset=utf-8",
|
|
1774
|
+
"Cache-Control": "no-cache, no-transform",
|
|
1775
|
+
"Connection": "keep-alive",
|
|
1776
|
+
"X-Accel-Buffering": "no"
|
|
1777
|
+
}
|
|
1778
|
+
});
|
|
1779
|
+
});
|
|
1619
1780
|
app.get("/api/sessions", (c) => {
|
|
1620
1781
|
const query = c.req.query();
|
|
1621
1782
|
const q = typeof query.q === "string" ? query.q : void 0;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nextclaw/server",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.20",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Nextclaw UI/API server.",
|
|
6
6
|
"type": "module",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"@nextclaw/openclaw-compat": "^0.1.28",
|
|
19
19
|
"hono": "^4.6.2",
|
|
20
20
|
"ws": "^8.18.0",
|
|
21
|
-
"@nextclaw/core": "^0.6.
|
|
21
|
+
"@nextclaw/core": "^0.6.37"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
24
|
"@types/node": "^20.17.6",
|