@astralform/js 3.0.0 → 3.1.0

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.cjs CHANGED
@@ -541,6 +541,24 @@ var AstralformClient = class {
541
541
  avatarUrl: a.avatar_url
542
542
  }));
543
543
  }
544
+ /**
545
+ * List the models the caller may pick this turn — expanded from the curated
546
+ * catalog of the providers the team has connected (client-side model
547
+ * selection). Backs the composer's model picker. Scoped to the active agent
548
+ * via X-Agent-ID, same as {@link getAgentStatus}.
549
+ */
550
+ async getModels() {
551
+ const raw = await this.get("/v1/models");
552
+ return raw.map((m) => ({
553
+ provider: m.provider,
554
+ providerDisplay: m.provider_display,
555
+ model: m.model,
556
+ thinking: m.thinking,
557
+ tools: m.tools,
558
+ vision: m.vision,
559
+ thinkingMode: m.thinking_mode
560
+ }));
561
+ }
544
562
  async getSkills() {
545
563
  const raw = await this.get("/v1/skills");
546
564
  return raw.map((s) => ({
@@ -1292,6 +1310,11 @@ var ChatSession = class {
1292
1310
  this.emit({ type: "connected" });
1293
1311
  }
1294
1312
  async send(content, options) {
1313
+ if (options?.provider == null !== (options?.model == null)) {
1314
+ throw new Error(
1315
+ "`provider` and `model` must be supplied together (client-side model selection)."
1316
+ );
1317
+ }
1295
1318
  if (this.isStreaming) return;
1296
1319
  const conversationId = options?.conversationId ?? this.conversationId ?? void 0;
1297
1320
  const userMessage = {
@@ -1316,7 +1339,12 @@ var ChatSession = class {
1316
1339
  upload_ids: options?.uploadIds,
1317
1340
  agent_name: options?.agentName,
1318
1341
  enable_search: options?.enableSearch,
1319
- plan_mode: options?.planMode
1342
+ plan_mode: options?.planMode,
1343
+ // Per-request model choice (client-side model selection).
1344
+ provider: options?.provider,
1345
+ model: options?.model,
1346
+ reasoning_effort: options?.reasoningEffort,
1347
+ temperature: options?.temperature
1320
1348
  };
1321
1349
  await this.processStream(request);
1322
1350
  }
@@ -1674,17 +1702,12 @@ var ChatSession = class {
1674
1702
  ]);
1675
1703
  this.messages = messagesResult.status === "fulfilled" ? messagesResult.value : [];
1676
1704
  if (eventsResult.status === "fulfilled") {
1677
- let userMessageEmitted = !userMessageContent;
1705
+ if (userMessageContent) {
1706
+ this.emit({ type: "user_message", content: userMessageContent });
1707
+ }
1678
1708
  for (const ev of eventsResult.value) {
1679
1709
  const type = ev.data.type || ev.event;
1680
1710
  if (!type || type === "done") continue;
1681
- if (!userMessageEmitted && type === "message_start") {
1682
- this.emit({
1683
- type: "user_message",
1684
- content: userMessageContent
1685
- });
1686
- userMessageEmitted = true;
1687
- }
1688
1711
  const wire = { ...ev.data, type };
1689
1712
  try {
1690
1713
  await this.dispatchWireEvent(
@@ -1828,6 +1851,11 @@ var StreamManager = class {
1828
1851
  }
1829
1852
  // ── Send ──────────────────────────────────────────────────────
1830
1853
  async send(content, options) {
1854
+ if (options?.provider == null !== (options?.model == null)) {
1855
+ throw new Error(
1856
+ "`provider` and `model` must be supplied together (client-side model selection)."
1857
+ );
1858
+ }
1831
1859
  if (this._state === "streaming") return;
1832
1860
  if (!this._activeConversationId) {
1833
1861
  const id = await this.session.createNewConversation();
@@ -1839,7 +1867,11 @@ var StreamManager = class {
1839
1867
  enableSearch: options?.enableSearch,
1840
1868
  agentName: options?.agentName,
1841
1869
  uploadIds: options?.uploadIds,
1842
- planMode: options?.planMode
1870
+ planMode: options?.planMode,
1871
+ provider: options?.provider,
1872
+ model: options?.model,
1873
+ reasoningEffort: options?.reasoningEffort,
1874
+ temperature: options?.temperature
1843
1875
  });
1844
1876
  } catch {
1845
1877
  }
@@ -1993,21 +2025,21 @@ function mapSseToChat(raw) {
1993
2025
  function replayEvents(sseEvents, userMessages, handleEvent, addBlock) {
1994
2026
  const userMsgs = userMessages.filter((m) => m.role === "user");
1995
2027
  let userIdx = 0;
1996
- let expectingUserMessage = true;
2028
+ let currentJobId = null;
1997
2029
  for (const raw of sseEvents) {
1998
2030
  const type = raw.data.type || raw.event;
1999
- if (type === "message_stop") {
2000
- expectingUserMessage = true;
2001
- }
2002
- if (type === "message_start" && expectingUserMessage && userIdx < userMsgs.length) {
2003
- const userMsg = userMsgs[userIdx];
2004
- addBlock({
2005
- type: "user",
2006
- id: `replay_user_${userIdx}`,
2007
- content: userMsg.content
2008
- });
2009
- userIdx++;
2010
- expectingUserMessage = false;
2031
+ if (!type || type === "done") continue;
2032
+ const jobId = raw.data.job_id ?? null;
2033
+ if (jobId !== null && jobId !== currentJobId) {
2034
+ currentJobId = jobId;
2035
+ if (userIdx < userMsgs.length) {
2036
+ addBlock({
2037
+ type: "user",
2038
+ id: `replay_user_${userIdx}`,
2039
+ content: userMsgs[userIdx].content
2040
+ });
2041
+ userIdx++;
2042
+ }
2011
2043
  }
2012
2044
  for (const ce of mapSseToChat(raw)) {
2013
2045
  handleEvent(ce);