chainlesschain 0.45.74 → 0.45.76

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.
Files changed (41) hide show
  1. package/README.md +52 -15
  2. package/package.json +1 -1
  3. package/src/assets/web-panel/.build-hash +1 -1
  4. package/src/assets/web-panel/assets/{AppLayout-BhJ3YFWt.js → AppLayout-2RCrdXxl.js} +1 -1
  5. package/src/assets/web-panel/assets/AppLayout-D9pBLPC3.css +1 -0
  6. package/src/assets/web-panel/assets/{Chat-DaxTP3x8.js → Chat-B2nB8o_F.js} +1 -1
  7. package/src/assets/web-panel/assets/{Dashboard-CjlX4CrX.js → Dashboard-DanoHPSI.js} +1 -1
  8. package/src/assets/web-panel/assets/{Skills-BCvgBkD3.js → Skills-CLlblJcG.js} +1 -1
  9. package/src/assets/web-panel/assets/chat-DWBA4-cl.js +1 -0
  10. package/src/assets/web-panel/assets/{index-DrmEk9S3.js → index-CyGtHm63.js} +2 -2
  11. package/src/assets/web-panel/index.html +1 -1
  12. package/src/commands/learning.js +273 -0
  13. package/src/commands/lowcode.js +23 -8
  14. package/src/gateways/discord/discord-formatter.js +89 -0
  15. package/src/gateways/gateway-base.js +189 -0
  16. package/src/gateways/telegram/telegram-formatter.js +93 -0
  17. package/src/index.js +2 -0
  18. package/src/lib/app-builder.js +136 -8
  19. package/src/lib/autonomous-agent.js +8 -1
  20. package/src/lib/cli-context-engineering.js +15 -0
  21. package/src/lib/execution-backend.js +239 -0
  22. package/src/lib/hook-manager.js +2 -0
  23. package/src/lib/iteration-budget.js +175 -0
  24. package/src/lib/learning/learning-hooks.js +117 -0
  25. package/src/lib/learning/learning-tables.js +66 -0
  26. package/src/lib/learning/outcome-feedback.js +243 -0
  27. package/src/lib/learning/reflection-engine.js +323 -0
  28. package/src/lib/learning/skill-improver.js +536 -0
  29. package/src/lib/learning/skill-synthesizer.js +315 -0
  30. package/src/lib/learning/trajectory-store.js +409 -0
  31. package/src/lib/plugin-autodiscovery.js +224 -0
  32. package/src/lib/session-search.js +193 -0
  33. package/src/lib/sub-agent-context.js +7 -2
  34. package/src/lib/user-profile.js +172 -0
  35. package/src/lib/web-ui-server.js +1 -1
  36. package/src/repl/agent-repl.js +109 -0
  37. package/src/runtime/agent-core.js +75 -4
  38. package/src/runtime/coding-agent-contract-shared.cjs +35 -0
  39. package/src/runtime/coding-agent-policy.cjs +10 -0
  40. package/src/assets/web-panel/assets/AppLayout-Cr2lWhF-.css +0 -1
  41. package/src/assets/web-panel/assets/chat-BmwHBi9M.js +0 -1
@@ -51,6 +51,7 @@ import { feature } from "../lib/feature-flags.js";
51
51
  import { recordCompressionMetric } from "../lib/compression-telemetry.js";
52
52
  import { fireSessionHook } from "../lib/session-hooks.js";
53
53
  import { HookEvents } from "../lib/hook-manager.js";
54
+ import { IterationBudget } from "../lib/iteration-budget.js";
54
55
  import {
55
56
  AGENT_TOOLS,
56
57
  buildSystemPrompt,
@@ -91,6 +92,12 @@ async function agentLoop(messages, options) {
91
92
  } else if (event.result?.success) {
92
93
  process.stdout.write(chalk.green(` Done\n`));
93
94
  }
95
+ } else if (event.type === "iteration-warning") {
96
+ process.stdout.write(chalk.yellow(`\n ${event.message}\n`));
97
+ } else if (event.type === "iteration-budget-exhausted") {
98
+ process.stdout.write(
99
+ chalk.red(`\n [Budget Exhausted] ${event.budget}\n`),
100
+ );
94
101
  } else if (event.type === "response-complete") {
95
102
  return event.content;
96
103
  }
@@ -314,6 +321,12 @@ export async function startAgentRepl(options = {}) {
314
321
  logger.log(
315
322
  ` ${chalk.cyan("/cowork")} Multi-agent collaboration (debate, compare)`,
316
323
  );
324
+ logger.log(
325
+ ` ${chalk.cyan("/search")} Search past sessions (/search <query>)`,
326
+ );
327
+ logger.log(
328
+ ` ${chalk.cyan("/profile")} Show/edit user profile (USER.md)`,
329
+ );
317
330
  logger.log(
318
331
  ` ${chalk.cyan("/plan")} Enter plan mode (read-only analysis first)`,
319
332
  );
@@ -559,6 +572,100 @@ export async function startAgentRepl(options = {}) {
559
572
  return;
560
573
  }
561
574
 
575
+ // Session search
576
+ if (trimmed.startsWith("/search")) {
577
+ const searchQuery = trimmed.slice(7).trim();
578
+ if (!searchQuery) {
579
+ logger.info("Usage: /search <query>");
580
+ prompt();
581
+ return;
582
+ }
583
+ if (!db) {
584
+ logger.info("Database not available for session search");
585
+ prompt();
586
+ return;
587
+ }
588
+ try {
589
+ const { SessionSearchIndex } = await import("../lib/session-search.js");
590
+ const index = new SessionSearchIndex(db);
591
+ index.ensureTables();
592
+ const results = index.search(searchQuery, { limit: 10 });
593
+ if (results.length === 0) {
594
+ logger.info(
595
+ "No results found. Try /search after a few sessions, or run reindex.",
596
+ );
597
+ } else {
598
+ logger.log(chalk.bold(`\nSearch results for "${searchQuery}":\n`));
599
+ for (const r of results) {
600
+ const snippet = (r.snippet || "").substring(0, 120);
601
+ logger.log(
602
+ ` ${chalk.cyan(r.sessionId.substring(0, 20))} [${chalk.dim(r.role)}] ${snippet}`,
603
+ );
604
+ }
605
+ logger.log("");
606
+ }
607
+ } catch (err) {
608
+ logger.error(`Search failed: ${err.message}`);
609
+ }
610
+ prompt();
611
+ return;
612
+ }
613
+
614
+ // User profile commands
615
+ if (trimmed.startsWith("/profile")) {
616
+ const profileArg = trimmed.slice(8).trim();
617
+ try {
618
+ const { readUserProfile, updateUserProfile, getUserProfilePath } =
619
+ await import("../lib/user-profile.js");
620
+
621
+ if (!profileArg || profileArg === "show") {
622
+ const content = readUserProfile();
623
+ if (content) {
624
+ logger.log(chalk.bold("\nUser Profile (USER.md):\n"));
625
+ logger.log(content);
626
+ logger.log(chalk.dim(`\nPath: ${getUserProfilePath()}`));
627
+ logger.log("");
628
+ } else {
629
+ logger.info(
630
+ `No user profile yet. Use /profile set <content> or let the agent learn your preferences.`,
631
+ );
632
+ }
633
+ } else if (profileArg.startsWith("set ")) {
634
+ const newContent = profileArg.slice(4).trim();
635
+ if (!newContent) {
636
+ logger.info("Usage: /profile set <content>");
637
+ } else {
638
+ const result = updateUserProfile(newContent);
639
+ if (result.written) {
640
+ logger.info(
641
+ `Profile updated (${result.length} chars${result.truncated ? ", truncated" : ""})`,
642
+ );
643
+ } else {
644
+ logger.error("Failed to write profile");
645
+ }
646
+ }
647
+ } else if (profileArg === "clear") {
648
+ updateUserProfile("");
649
+ logger.info("Profile cleared.");
650
+ } else if (profileArg === "path") {
651
+ logger.info(`Profile path: ${getUserProfilePath()}`);
652
+ } else {
653
+ logger.log(chalk.bold("\nProfile Commands:"));
654
+ logger.log(` ${chalk.cyan("/profile")} Show user profile`);
655
+ logger.log(
656
+ ` ${chalk.cyan("/profile set <content>")} Update profile`,
657
+ );
658
+ logger.log(` ${chalk.cyan("/profile clear")} Clear profile`);
659
+ logger.log(` ${chalk.cyan("/profile path")} Show file path`);
660
+ logger.log("");
661
+ }
662
+ } catch (err) {
663
+ logger.error(`Profile command failed: ${err.message}`);
664
+ }
665
+ prompt();
666
+ return;
667
+ }
668
+
562
669
  // Cowork commands
563
670
  if (trimmed.startsWith("/cowork")) {
564
671
  const coworkArgs = trimmed.slice(7).trim();
@@ -1108,12 +1215,14 @@ export async function startAgentRepl(options = {}) {
1108
1215
 
1109
1216
  try {
1110
1217
  process.stdout.write("\n");
1218
+ const iterationBudget = new IterationBudget({ owner: sessionId });
1111
1219
  const response = await agentLoop(messages, {
1112
1220
  provider,
1113
1221
  model: activeModel,
1114
1222
  baseUrl,
1115
1223
  apiKey,
1116
1224
  contextEngine,
1225
+ iterationBudget,
1117
1226
  });
1118
1227
 
1119
1228
  if (response) {
@@ -780,6 +780,33 @@ async function executeToolInner(
780
780
  );
781
781
  }
782
782
 
783
+ case "search_sessions": {
784
+ try {
785
+ const { SessionSearchIndex } = await import("../lib/session-search.js");
786
+ const { bootstrap } = await import("./bootstrap.js");
787
+ const ctx = await bootstrap({ verbose: false });
788
+ if (!ctx.db) {
789
+ return attachDescriptor({
790
+ error: "Database not available for session search",
791
+ });
792
+ }
793
+ const index = new SessionSearchIndex(ctx.db);
794
+ index.ensureTables();
795
+ const results = index.search(args.query, {
796
+ limit: args.limit || 10,
797
+ });
798
+ return attachDescriptor({
799
+ query: args.query,
800
+ results,
801
+ count: results.length,
802
+ });
803
+ } catch (err) {
804
+ return attachDescriptor({
805
+ error: `Session search failed: ${err.message}`,
806
+ });
807
+ }
808
+ }
809
+
783
810
  case "search_files": {
784
811
  const dir = args.directory ? path.resolve(cwd, args.directory) : cwd;
785
812
  try {
@@ -1583,7 +1610,12 @@ function _normalizeAnthropicResponse(data) {
1583
1610
  * @param {object} options - provider, model, baseUrl, apiKey, contextEngine, hookDb, skillLoader, cwd, slotFiller, interaction
1584
1611
  */
1585
1612
  export async function* agentLoop(messages, options) {
1586
- const MAX_ITERATIONS = 15;
1613
+ // Shared iteration budget — replaces hardcoded MAX_ITERATIONS.
1614
+ // When options.iterationBudget is provided (e.g. from parent agent),
1615
+ // the same budget instance is shared, so parent+child consume from one pool.
1616
+ const { IterationBudget, WarningLevel } =
1617
+ await import("../lib/iteration-budget.js");
1618
+ const budget = options.iterationBudget || new IterationBudget();
1587
1619
  const signal = options.signal || null;
1588
1620
  const toolContext = {
1589
1621
  hookDb: options.hookDb || null,
@@ -1656,8 +1688,36 @@ export async function* agentLoop(messages, options) {
1656
1688
  // real `chatWithTools`.
1657
1689
  const llmCall = options.chatFn || chatWithTools;
1658
1690
 
1659
- for (let i = 0; i < MAX_ITERATIONS; i++) {
1691
+ while (budget.hasRemaining()) {
1692
+ budget.consume();
1660
1693
  throwIfAborted(signal);
1694
+
1695
+ // Emit progressive warnings (once per level)
1696
+ const level = budget.warningLevel();
1697
+ if (
1698
+ level === WarningLevel.WARNING &&
1699
+ !budget.hasWarned(WarningLevel.WARNING)
1700
+ ) {
1701
+ budget.recordWarning(WarningLevel.WARNING);
1702
+ yield {
1703
+ type: "iteration-warning",
1704
+ level,
1705
+ message: budget.toWarningMessage(),
1706
+ budget: budget.toSummary(),
1707
+ };
1708
+ } else if (
1709
+ level === WarningLevel.WRAPPING_UP &&
1710
+ !budget.hasWarned(WarningLevel.WRAPPING_UP)
1711
+ ) {
1712
+ budget.recordWarning(WarningLevel.WRAPPING_UP);
1713
+ yield {
1714
+ type: "iteration-warning",
1715
+ level,
1716
+ message: budget.toWarningMessage(),
1717
+ budget: budget.toSummary(),
1718
+ };
1719
+ }
1720
+
1661
1721
  const result = await llmCall(messages, options);
1662
1722
  throwIfAborted(signal);
1663
1723
  const msg = result?.message;
@@ -1705,6 +1765,13 @@ export async function* agentLoop(messages, options) {
1705
1765
 
1706
1766
  throwIfAborted(signal);
1707
1767
 
1768
+ // Append budget warning to tool result so the LLM sees it
1769
+ const warningMsg = budget.toWarningMessage();
1770
+ const resultStr = JSON.stringify(toolResult).substring(0, 5000);
1771
+ const toolContent = warningMsg
1772
+ ? `${resultStr}\n\n${warningMsg}`
1773
+ : resultStr;
1774
+
1708
1775
  yield {
1709
1776
  type: "tool-result",
1710
1777
  tool: toolName,
@@ -1714,15 +1781,17 @@ export async function* agentLoop(messages, options) {
1714
1781
 
1715
1782
  messages.push({
1716
1783
  role: "tool",
1717
- content: JSON.stringify(toolResult).substring(0, 5000),
1784
+ content: toolContent,
1718
1785
  tool_call_id: call.id,
1719
1786
  });
1720
1787
  }
1721
1788
  }
1722
1789
 
1790
+ // Budget exhausted — yield exhaustion event + final message
1791
+ yield { type: "iteration-budget-exhausted", budget: budget.toSummary() };
1723
1792
  yield {
1724
1793
  type: "response-complete",
1725
- content: "(Reached max tool call iterations)",
1794
+ content: `(Iteration budget exhausted ${budget.toSummary()})`,
1726
1795
  };
1727
1796
  }
1728
1797
 
@@ -1754,6 +1823,8 @@ export function formatToolArgs(name, args) {
1754
1823
  return `${args.language} (${(args.code || "").length} chars)`;
1755
1824
  case "spawn_sub_agent":
1756
1825
  return `[${args.role}] ${(args.task || "").substring(0, 60)}`;
1826
+ case "search_sessions":
1827
+ return `"${(args.query || "").substring(0, 60)}"`;
1757
1828
  default:
1758
1829
  return JSON.stringify(args).substring(0, 60);
1759
1830
  }
@@ -403,6 +403,41 @@ const CODING_AGENT_TOOL_CONTRACTS = Object.freeze([
403
403
  tags: ["tool:spawn_sub_agent", "contract:coding-agent", "tier:extension"],
404
404
  },
405
405
  },
406
+ {
407
+ name: "search_sessions",
408
+ title: "Search Sessions",
409
+ kind: "search",
410
+ tier: "extension",
411
+ description:
412
+ "Search across all past agent session conversations using full-text search. Useful for finding prior context, decisions, or code discussed in previous sessions.",
413
+ inputSchema: {
414
+ type: "object",
415
+ properties: {
416
+ query: {
417
+ type: "string",
418
+ description: "Search query (supports natural language keywords)",
419
+ },
420
+ limit: {
421
+ type: "number",
422
+ description: "Maximum number of results to return (default: 10)",
423
+ },
424
+ },
425
+ required: ["query"],
426
+ },
427
+ ...TOOL_POLICY_METADATA.search_sessions,
428
+ permissions: {
429
+ level: "readonly",
430
+ scopes: ["session:read"],
431
+ },
432
+ telemetry: {
433
+ category: "search",
434
+ tags: [
435
+ "tool:search_sessions",
436
+ "contract:coding-agent",
437
+ "tier:extension",
438
+ ],
439
+ },
440
+ },
406
441
  ]);
407
442
 
408
443
  const CODING_AGENT_MVP_TOOL_NAMES = Object.freeze(
@@ -125,6 +125,16 @@ const TOOL_POLICY_METADATA = Object.freeze({
125
125
  approvalFlow: "auto",
126
126
  isReadOnly: true,
127
127
  },
128
+ search_sessions: {
129
+ riskLevel: RISK_LEVELS.LOW,
130
+ category: TOOL_CATEGORIES.SEARCH,
131
+ availableInPlanMode: true,
132
+ planModeBehavior: "allow",
133
+ requiresPlanApproval: false,
134
+ requiresConfirmation: false,
135
+ approvalFlow: "auto",
136
+ isReadOnly: true,
137
+ },
128
138
  run_skill: {
129
139
  riskLevel: RISK_LEVELS.MEDIUM,
130
140
  category: TOOL_CATEGORIES.SKILL,
@@ -1 +0,0 @@
1
- .app-root[data-v-d166fd5f]{min-height:100vh;background:var(--bg-base)}.sidebar[data-v-d166fd5f]{background:var(--bg-sidebar)!important;border-right:1px solid var(--border-color);transition:background .25s}.main-area[data-v-d166fd5f]{background:var(--bg-base)}.logo[data-v-d166fd5f]{height:52px;display:flex;align-items:center;padding:0 18px;gap:10px;border-bottom:1px solid var(--border-color);overflow:hidden;white-space:nowrap;flex-shrink:0}.logo.collapsed[data-v-d166fd5f]{padding:0;justify-content:center}.logo-icon[data-v-d166fd5f]{font-size:20px;flex-shrink:0}.logo-text[data-v-d166fd5f]{color:var(--logo-text);font-weight:700;font-size:14px;letter-spacing:.01em}.mode-banner[data-v-d166fd5f]{display:flex;align-items:center;gap:8px;padding:7px 10px;margin:8px 8px 4px;border-radius:7px;overflow:hidden}.mode-banner.project[data-v-d166fd5f]{background:#1677ff1a;border:1px solid rgba(22,119,255,.2)}.mode-banner.global[data-v-d166fd5f]{background:#722ed11a;border:1px solid rgba(114,46,209,.2)}.banner-icon[data-v-d166fd5f]{font-size:13px;flex-shrink:0;color:#1677ff}.mode-banner.global .banner-icon[data-v-d166fd5f]{color:#722ed1}.banner-info[data-v-d166fd5f]{flex:1;min-width:0}.banner-name[data-v-d166fd5f]{font-size:12px;font-weight:600;color:var(--text-primary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.banner-sub[data-v-d166fd5f]{font-size:10px;color:#1677ff;margin-top:1px}.mode-banner.global .banner-name[data-v-d166fd5f]{color:#c084fc}.mode-icon-sm[data-v-d166fd5f]{display:flex;justify-content:center;padding:8px 0;font-size:14px}.side-menu[data-v-d166fd5f]{border:none!important;margin-top:2px;-webkit-user-select:none;user-select:none;background:transparent!important}.group-label[data-v-d166fd5f]{color:var(--group-title);font-size:10px;font-weight:700;letter-spacing:.12em;padding-left:6px}[data-v-d166fd5f] .ant-menu-item-group-title{padding:8px 16px 2px!important}[data-v-d166fd5f] .ant-menu-item{height:38px!important;line-height:38px!important;margin:1px 4px!important;border-radius:6px!important}.divider-sm[data-v-d166fd5f]{margin:4px 0!important}.sidebar-footer[data-v-d166fd5f]{position:absolute;bottom:48px;left:0;right:0;padding:8px 18px;display:flex;align-items:center;gap:8px;border-top:1px solid var(--border-color)}.sidebar-footer.collapsed[data-v-d166fd5f]{justify-content:center;padding:8px 0}.footer-text[data-v-d166fd5f]{color:var(--text-secondary);font-size:11px}.app-header[data-v-d166fd5f]{background:var(--bg-header)!important;padding:0 20px!important;border-bottom:1px solid var(--border-color);height:50px!important;line-height:50px!important;display:flex!important;align-items:center!important;justify-content:space-between!important;box-shadow:0 1px 4px #0000000f}.header-left[data-v-d166fd5f],.header-right[data-v-d166fd5f]{display:flex;align-items:center;gap:10px}.scope-tag[data-v-d166fd5f]{display:flex;align-items:center;gap:5px;padding:3px 10px;border-radius:5px;font-size:12px;font-weight:500}.scope-tag.project[data-v-d166fd5f]{background:#1677ff1a;color:#1677ff;border:1px solid rgba(22,119,255,.2)}.scope-tag.global[data-v-d166fd5f]{background:#722ed11a;color:#722ed1;border:1px solid rgba(114,46,209,.2)}.info-icon[data-v-d166fd5f]{opacity:.45;cursor:help;margin-left:2px}.theme-switcher[data-v-d166fd5f]{display:flex;align-items:center;gap:4px;background:var(--bg-card);border:1px solid var(--border-color);border-radius:20px;padding:3px 6px}.theme-btn[data-v-d166fd5f]{width:26px;height:26px;border:none;border-radius:50%;cursor:pointer;background:transparent;font-size:14px;line-height:1;display:flex;align-items:center;justify-content:center;transition:background .15s,transform .15s;opacity:.55}.theme-btn[data-v-d166fd5f]:hover{opacity:.9;transform:scale(1.15);background:var(--bg-card-hover)}.theme-btn.active[data-v-d166fd5f]{opacity:1;transform:scale(1.1);background:var(--bg-card-hover);outline:2px solid var(--text-secondary)}.version-tag[data-v-d166fd5f]{color:var(--text-muted);font-size:11px}.ws-tag[data-v-d166fd5f]{margin:0!important;font-size:11px}.page-content[data-v-d166fd5f]{padding:24px;overflow:auto;background:var(--bg-base);min-height:calc(100vh - 50px)}
@@ -1 +0,0 @@
1
- import{V as j,f as g,r as w}from"./vendor-CN0Iv_qZ.js";import{u as f}from"./ws-CU7Gvoom.js";const S="新对话",T="新 Agent",M={"assistant.delta":"response-token","assistant.final":"response-complete","assistant.message":"response-complete","tool.call.started":"tool-executing","tool.call.completed":"tool-result","tool.call.failed":"tool-result","slot.filling":"question","approval.requested":"question",error:"error"},N=j("chat",()=>{const c=g([]),p=g(null),i=w({}),a=w({}),m=w({}),d=g(!1);let q=null;function y(t){return i[t]||(i[t]=[]),i[t]}function h(t){if(!t?.id)return;const e=c.value.find(o=>o.id===t.id);if(e){Object.assign(e,t);return}c.value.unshift(t)}function A(t,e=f()){i[t]||(i[t]=[]),a[t]||(a[t]={content:"",active:!1}),e.onSession(t,o=>E(t,o))}function v(t=f()){q||(q=t.onRuntimeEvent(e=>{const o=e.payload||{},s=o.record||{};if(e.type==="session:start"){const n=o.sessionType||s.type||"chat";h({id:o.sessionId,type:n,provider:s.provider||null,model:s.model||null,projectRoot:s.projectRoot||null,status:s.status||"created",title:n==="chat"?S:T,createdAt:Date.now(),messageCount:s.messageCount??0})}else if(e.type==="session:resume"){const n=o.sessionId;if(!n)return;Array.isArray(o.history)&&(i[n]=o.history.map(r=>({role:r.role,content:r.content,timestamp:r.timestamp||Date.now()}))),a[n]||(a[n]={content:"",active:!1}),h({id:n,type:s.type||null,provider:s.provider||null,model:s.model||null,projectRoot:s.projectRoot||null,status:s.status||"resumed",messageCount:s.messageCount??(Array.isArray(o.history)?o.history.length:0)})}else if(e.type==="session:end"){const n=o.sessionId;c.value=c.value.filter(r=>r.id!==n),p.value===n&&(p.value=c.value[0]?.id||null)}}))}async function C(){const t=f();v(t),c.value=await t.listSessions()}async function D(t="chat"){const e=f();v(e);const o=await e.createSession(t);return h({id:o,type:t,title:t==="chat"?S:T,createdAt:Date.now(),messageCount:0}),A(o,e),p.value=o,o}function E(t,e){const o=y(t),s=M[e.type]||e.type,n=e.payload||{};if(s==="response-token"){a[t]||(a[t]={content:"",active:!0});const r=e.token||n.token||n.delta||n.content||"";a[t].content+=r,a[t].active=!0}else if(s==="response-complete"){const r=e.content||n.content||a[t]?.content||"";o.push({role:"assistant",content:r,timestamp:Date.now()}),a[t]&&(a[t].content="",a[t].active=!1);const l=c.value.find(u=>u.id===t);if(l&&(l.title===S||l.title===T)){const u=o.find(L=>L.role==="user");u&&(l.title=u.content.slice(0,30))}l&&(l.messageCount=o.filter(u=>u.role!=="tool").length),d.value=!1}else if(s==="tool-executing")o.push({role:"tool",tool:e.tool||n.tool||n.toolName||"unknown",input:e.input||n.input||n.args||null,status:"running",timestamp:Date.now()});else if(s==="tool-result"){const r=e.tool||n.tool||n.toolName||"unknown",l=[...o].reverse().find(u=>u.role==="tool"&&u.tool===r);l&&(l.result=e.result||n.result||n.output||null,l.status="done")}else if(s==="question")m[t]={requestId:e.requestId||n.requestId||e.id,question:e.question||n.question||n.message||"",choices:e.choices||n.choices||n.options||[]};else if(s==="error"){const r=e.message||n.message||"Unknown error";o.push({role:"assistant",content:`Error: ${r}`,timestamp:Date.now()}),d.value=!1,a[t]&&(a[t].active=!1)}}async function k(t,e){const o=f();v(o),y(t).push({role:"user",content:e,timestamp:Date.now()}),a[t]||(a[t]={content:"",active:!1}),a[t].active=!0,d.value=!0,o.sendSessionMessage(t,e)}function _(t,e){const o=f(),s=m[t];s&&(o.answerQuestion(t,s.requestId,e),delete m[t])}async function R(t){const e=f();if(v(e),p.value=t,A(t,e),!i[t]||i[t].length===0)try{await e.resumeSession(t)}catch{}}return{sessions:c,currentSessionId:p,messages:i,streaming:a,pendingQuestion:m,isLoading:d,loadSessions:C,createSession:D,sendMessage:k,answerQuestion:_,switchSession:R,getMessages:y}});export{N as u};