@nextclaw/server 0.5.18 → 0.5.19

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 CHANGED
@@ -206,6 +206,16 @@ type ChatTurnResult = {
206
206
  model?: string;
207
207
  metadata?: Record<string, unknown>;
208
208
  };
209
+ type ChatTurnStreamEvent = {
210
+ type: "delta";
211
+ delta: string;
212
+ } | {
213
+ type: "final";
214
+ result: ChatTurnResult;
215
+ } | {
216
+ type: "error";
217
+ error: string;
218
+ };
209
219
  type ChatTurnView = {
210
220
  reply: string;
211
221
  sessionKey: string;
@@ -217,6 +227,7 @@ type ChatTurnView = {
217
227
  };
218
228
  type UiChatRuntime = {
219
229
  processTurn: (params: ChatTurnRequest) => Promise<ChatTurnResult>;
230
+ processTurnStream?: (params: ChatTurnRequest) => AsyncGenerator<ChatTurnStreamEvent>;
220
231
  };
221
232
  type ConfigView = {
222
233
  agents: {
@@ -568,4 +579,4 @@ declare function deleteSession(configPath: string, key: string): boolean;
568
579
  declare function updateRuntime(configPath: string, patch: RuntimeConfigUpdate): Pick<ConfigView, "agents" | "bindings" | "session">;
569
580
  declare function updateSecrets(configPath: string, patch: SecretsConfigUpdate): SecretsView;
570
581
 
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 };
582
+ 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 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
@@ -819,6 +819,24 @@ function resolveAgentIdFromSessionKey(sessionKey) {
819
819
  const agentId = readNonEmptyString(parsed?.agentId);
820
820
  return agentId;
821
821
  }
822
+ function buildChatTurnView(params) {
823
+ const completedAt = /* @__PURE__ */ new Date();
824
+ return {
825
+ reply: String(params.result.reply ?? ""),
826
+ sessionKey: readNonEmptyString(params.result.sessionKey) ?? params.fallbackSessionKey,
827
+ ...readNonEmptyString(params.result.agentId) || params.requestedAgentId ? { agentId: readNonEmptyString(params.result.agentId) ?? params.requestedAgentId } : {},
828
+ ...readNonEmptyString(params.result.model) || params.requestedModel ? { model: readNonEmptyString(params.result.model) ?? params.requestedModel } : {},
829
+ requestedAt: params.requestedAt.toISOString(),
830
+ completedAt: completedAt.toISOString(),
831
+ durationMs: Math.max(0, completedAt.getTime() - params.startedAtMs)
832
+ };
833
+ }
834
+ function toSseFrame(event, data) {
835
+ return `event: ${event}
836
+ data: ${JSON.stringify(data)}
837
+
838
+ `;
839
+ }
822
840
  function normalizeMarketplaceBaseUrl(options) {
823
841
  const fromOptions = options.marketplace?.apiBaseUrl?.trim();
824
842
  const fromEnv = process.env.NEXTCLAW_MARKETPLACE_API_BASE?.trim();
@@ -1600,22 +1618,134 @@ function createUiRouter(options) {
1600
1618
  };
1601
1619
  try {
1602
1620
  const result = await options.chatRuntime.processTurn(request);
1603
- const completedAt = /* @__PURE__ */ new Date();
1604
- const response = {
1605
- reply: String(result.reply ?? ""),
1606
- sessionKey: readNonEmptyString(result.sessionKey) ?? sessionKey,
1607
- ...readNonEmptyString(result.agentId) || requestedAgentId ? { agentId: readNonEmptyString(result.agentId) ?? requestedAgentId } : {},
1608
- ...readNonEmptyString(result.model) || requestedModel ? { model: readNonEmptyString(result.model) ?? requestedModel } : {},
1609
- requestedAt: requestedAt.toISOString(),
1610
- completedAt: completedAt.toISOString(),
1611
- durationMs: Math.max(0, completedAt.getTime() - startedAtMs)
1612
- };
1621
+ const response = buildChatTurnView({
1622
+ result,
1623
+ fallbackSessionKey: sessionKey,
1624
+ requestedAgentId,
1625
+ requestedModel,
1626
+ requestedAt,
1627
+ startedAtMs
1628
+ });
1613
1629
  options.publish({ type: "config.updated", payload: { path: "session" } });
1614
1630
  return c.json(ok(response));
1615
1631
  } catch (error) {
1616
1632
  return c.json(err("CHAT_TURN_FAILED", String(error)), 500);
1617
1633
  }
1618
1634
  });
1635
+ app.post("/api/chat/turn/stream", async (c) => {
1636
+ const chatRuntime = options.chatRuntime;
1637
+ if (!chatRuntime) {
1638
+ return c.json(err("NOT_AVAILABLE", "chat runtime unavailable"), 503);
1639
+ }
1640
+ const body = await readJson(c.req.raw);
1641
+ if (!body.ok) {
1642
+ return c.json(err("INVALID_BODY", "invalid json body"), 400);
1643
+ }
1644
+ const message = readNonEmptyString(body.data.message);
1645
+ if (!message) {
1646
+ return c.json(err("INVALID_BODY", "message is required"), 400);
1647
+ }
1648
+ const sessionKey = readNonEmptyString(body.data.sessionKey) ?? `ui:${Date.now().toString(36)}:${Math.random().toString(36).slice(2, 8)}`;
1649
+ const requestedAt = /* @__PURE__ */ new Date();
1650
+ const startedAtMs = requestedAt.getTime();
1651
+ const metadata = isRecord(body.data.metadata) ? body.data.metadata : void 0;
1652
+ const requestedAgentId = readNonEmptyString(body.data.agentId) ?? resolveAgentIdFromSessionKey(sessionKey);
1653
+ const requestedModel = readNonEmptyString(body.data.model);
1654
+ const request = {
1655
+ message,
1656
+ sessionKey,
1657
+ channel: readNonEmptyString(body.data.channel) ?? "ui",
1658
+ chatId: readNonEmptyString(body.data.chatId) ?? "web-ui",
1659
+ ...requestedAgentId ? { agentId: requestedAgentId } : {},
1660
+ ...requestedModel ? { model: requestedModel } : {},
1661
+ ...metadata ? { metadata } : {}
1662
+ };
1663
+ const encoder = new TextEncoder();
1664
+ const stream = new ReadableStream({
1665
+ start: async (controller) => {
1666
+ const push = (event, data) => {
1667
+ controller.enqueue(encoder.encode(toSseFrame(event, data)));
1668
+ };
1669
+ try {
1670
+ push("ready", {
1671
+ sessionKey,
1672
+ requestedAt: requestedAt.toISOString()
1673
+ });
1674
+ const streamTurn = chatRuntime.processTurnStream;
1675
+ if (!streamTurn) {
1676
+ const result = await chatRuntime.processTurn(request);
1677
+ const response = buildChatTurnView({
1678
+ result,
1679
+ fallbackSessionKey: sessionKey,
1680
+ requestedAgentId,
1681
+ requestedModel,
1682
+ requestedAt,
1683
+ startedAtMs
1684
+ });
1685
+ push("final", response);
1686
+ options.publish({ type: "config.updated", payload: { path: "session" } });
1687
+ push("done", { ok: true });
1688
+ return;
1689
+ }
1690
+ let hasFinal = false;
1691
+ for await (const event of streamTurn(request)) {
1692
+ const typed = event;
1693
+ if (typed.type === "delta") {
1694
+ if (typed.delta) {
1695
+ push("delta", { delta: typed.delta });
1696
+ }
1697
+ continue;
1698
+ }
1699
+ if (typed.type === "final") {
1700
+ const response = buildChatTurnView({
1701
+ result: typed.result,
1702
+ fallbackSessionKey: sessionKey,
1703
+ requestedAgentId,
1704
+ requestedModel,
1705
+ requestedAt,
1706
+ startedAtMs
1707
+ });
1708
+ hasFinal = true;
1709
+ push("final", response);
1710
+ options.publish({ type: "config.updated", payload: { path: "session" } });
1711
+ continue;
1712
+ }
1713
+ if (typed.type === "error") {
1714
+ push("error", {
1715
+ code: "CHAT_TURN_FAILED",
1716
+ message: typed.error
1717
+ });
1718
+ return;
1719
+ }
1720
+ }
1721
+ if (!hasFinal) {
1722
+ push("error", {
1723
+ code: "CHAT_TURN_FAILED",
1724
+ message: "stream ended without a final result"
1725
+ });
1726
+ return;
1727
+ }
1728
+ push("done", { ok: true });
1729
+ } catch (error) {
1730
+ push("error", {
1731
+ code: "CHAT_TURN_FAILED",
1732
+ message: String(error)
1733
+ });
1734
+ } finally {
1735
+ controller.close();
1736
+ }
1737
+ }
1738
+ });
1739
+ return new Response(stream, {
1740
+ status: 200,
1741
+ headers: {
1742
+ "Content-Type": "text/event-stream; charset=utf-8",
1743
+ "Cache-Control": "no-cache, no-transform",
1744
+ "Connection": "keep-alive",
1745
+ "X-Accel-Buffering": "no"
1746
+ }
1747
+ });
1748
+ });
1619
1749
  app.get("/api/sessions", (c) => {
1620
1750
  const query = c.req.query();
1621
1751
  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.18",
3
+ "version": "0.5.19",
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.35"
21
+ "@nextclaw/core": "^0.6.36"
22
22
  },
23
23
  "devDependencies": {
24
24
  "@types/node": "^20.17.6",