agent-orcha 0.0.4 → 0.0.7
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/README.md +216 -1323
- package/dist/lib/agents/agent-executor.d.ts +15 -4
- package/dist/lib/agents/agent-executor.d.ts.map +1 -1
- package/dist/lib/agents/agent-executor.js +337 -87
- package/dist/lib/agents/agent-executor.js.map +1 -1
- package/dist/lib/agents/agent-loader.d.ts +4 -1
- package/dist/lib/agents/agent-loader.d.ts.map +1 -1
- package/dist/lib/agents/agent-loader.js +20 -4
- package/dist/lib/agents/agent-loader.js.map +1 -1
- package/dist/lib/agents/index.d.ts +5 -5
- package/dist/lib/agents/index.js +4 -4
- package/dist/lib/agents/react-loop.d.ts +30 -0
- package/dist/lib/agents/react-loop.d.ts.map +1 -0
- package/dist/lib/agents/react-loop.js +193 -0
- package/dist/lib/agents/react-loop.js.map +1 -0
- package/dist/lib/agents/structured-output-wrapper.d.ts +3 -3
- package/dist/lib/agents/structured-output-wrapper.d.ts.map +1 -1
- package/dist/lib/agents/structured-output-wrapper.js +2 -2
- package/dist/lib/agents/structured-output-wrapper.js.map +1 -1
- package/dist/lib/agents/types.d.ts +306 -19
- package/dist/lib/agents/types.d.ts.map +1 -1
- package/dist/lib/agents/types.js +34 -4
- package/dist/lib/agents/types.js.map +1 -1
- package/dist/lib/functions/function-loader.d.ts +3 -1
- package/dist/lib/functions/function-loader.d.ts.map +1 -1
- package/dist/lib/functions/function-loader.js +23 -5
- package/dist/lib/functions/function-loader.js.map +1 -1
- package/dist/lib/functions/index.d.ts +2 -2
- package/dist/lib/functions/index.js +1 -1
- package/dist/lib/functions/simple-function-wrapper.d.ts +2 -11
- package/dist/lib/functions/simple-function-wrapper.d.ts.map +1 -1
- package/dist/lib/functions/simple-function-wrapper.js +3 -3
- package/dist/lib/functions/simple-function-wrapper.js.map +1 -1
- package/dist/lib/index.d.ts +29 -17
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/index.js +21 -9
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/integrations/collabnook.d.ts +56 -0
- package/dist/lib/integrations/collabnook.d.ts.map +1 -0
- package/dist/lib/integrations/collabnook.js +307 -0
- package/dist/lib/integrations/collabnook.js.map +1 -0
- package/dist/lib/integrations/email.d.ts +38 -0
- package/dist/lib/integrations/email.d.ts.map +1 -0
- package/dist/lib/integrations/email.js +249 -0
- package/dist/lib/integrations/email.js.map +1 -0
- package/dist/lib/integrations/integration-manager.d.ts +19 -0
- package/dist/lib/integrations/integration-manager.d.ts.map +1 -0
- package/dist/lib/integrations/integration-manager.js +159 -0
- package/dist/lib/integrations/integration-manager.js.map +1 -0
- package/dist/lib/integrations/types.d.ts +232 -0
- package/dist/lib/integrations/types.d.ts.map +1 -0
- package/dist/lib/integrations/types.js +37 -0
- package/dist/lib/integrations/types.js.map +1 -0
- package/dist/lib/knowledge/direct-mapper.d.ts +21 -0
- package/dist/lib/knowledge/direct-mapper.d.ts.map +1 -0
- package/dist/lib/knowledge/direct-mapper.js +134 -0
- package/dist/lib/knowledge/direct-mapper.js.map +1 -0
- package/dist/lib/knowledge/index.d.ts +9 -8
- package/dist/lib/knowledge/index.d.ts.map +1 -1
- package/dist/lib/knowledge/index.js +9 -7
- package/dist/lib/knowledge/index.js.map +1 -1
- package/dist/lib/knowledge/knowledge-store-metadata.d.ts +40 -0
- package/dist/lib/knowledge/knowledge-store-metadata.d.ts.map +1 -0
- package/dist/lib/knowledge/knowledge-store-metadata.js +93 -0
- package/dist/lib/knowledge/knowledge-store-metadata.js.map +1 -0
- package/dist/lib/knowledge/knowledge-store.d.ts +49 -0
- package/dist/lib/knowledge/knowledge-store.d.ts.map +1 -0
- package/dist/lib/knowledge/knowledge-store.js +670 -0
- package/dist/lib/knowledge/knowledge-store.js.map +1 -0
- package/dist/lib/knowledge/loaders/database-loader.d.ts +5 -5
- package/dist/lib/knowledge/loaders/database-loader.d.ts.map +1 -1
- package/dist/lib/knowledge/loaders/database-loader.js +21 -10
- package/dist/lib/knowledge/loaders/database-loader.js.map +1 -1
- package/dist/lib/knowledge/loaders/file-loaders.d.ts +45 -0
- package/dist/lib/knowledge/loaders/file-loaders.d.ts.map +1 -0
- package/dist/lib/knowledge/loaders/file-loaders.js +160 -0
- package/dist/lib/knowledge/loaders/file-loaders.js.map +1 -0
- package/dist/lib/knowledge/loaders/index.d.ts +3 -3
- package/dist/lib/knowledge/loaders/index.d.ts.map +1 -1
- package/dist/lib/knowledge/loaders/index.js +3 -3
- package/dist/lib/knowledge/loaders/index.js.map +1 -1
- package/dist/lib/knowledge/loaders/web-loader.d.ts +14 -5
- package/dist/lib/knowledge/loaders/web-loader.d.ts.map +1 -1
- package/dist/lib/knowledge/loaders/web-loader.js +64 -29
- package/dist/lib/knowledge/loaders/web-loader.js.map +1 -1
- package/dist/lib/knowledge/sqlite-store.d.ts +107 -0
- package/dist/lib/knowledge/sqlite-store.d.ts.map +1 -0
- package/dist/lib/knowledge/sqlite-store.js +327 -0
- package/dist/lib/knowledge/sqlite-store.js.map +1 -0
- package/dist/lib/knowledge/types.d.ts +124 -1448
- package/dist/lib/knowledge/types.d.ts.map +1 -1
- package/dist/lib/knowledge/types.js +54 -60
- package/dist/lib/knowledge/types.js.map +1 -1
- package/dist/lib/knowledge/utils/connection-pool.d.ts +3 -2
- package/dist/lib/knowledge/utils/connection-pool.d.ts.map +1 -1
- package/dist/lib/knowledge/utils/connection-pool.js +20 -10
- package/dist/lib/knowledge/utils/connection-pool.js.map +1 -1
- package/dist/lib/knowledge/utils/index.d.ts +2 -2
- package/dist/lib/knowledge/utils/index.js +2 -2
- package/dist/lib/llm/index.d.ts +5 -5
- package/dist/lib/llm/index.d.ts.map +1 -1
- package/dist/lib/llm/index.js +3 -3
- package/dist/lib/llm/index.js.map +1 -1
- package/dist/lib/llm/llm-call-logger.d.ts +39 -0
- package/dist/lib/llm/llm-call-logger.d.ts.map +1 -0
- package/dist/lib/llm/llm-call-logger.js +110 -0
- package/dist/lib/llm/llm-call-logger.js.map +1 -0
- package/dist/lib/llm/llm-config.d.ts +30 -16
- package/dist/lib/llm/llm-config.d.ts.map +1 -1
- package/dist/lib/llm/llm-config.js +22 -4
- package/dist/lib/llm/llm-config.js.map +1 -1
- package/dist/lib/llm/llm-factory.d.ts +3 -16
- package/dist/lib/llm/llm-factory.d.ts.map +1 -1
- package/dist/lib/llm/llm-factory.js +33 -48
- package/dist/lib/llm/llm-factory.js.map +1 -1
- package/dist/lib/llm/provider-detector.d.ts +1 -1
- package/dist/lib/llm/providers/anthropic-chat-model.d.ts +31 -0
- package/dist/lib/llm/providers/anthropic-chat-model.d.ts.map +1 -0
- package/dist/lib/llm/providers/anthropic-chat-model.js +262 -0
- package/dist/lib/llm/providers/anthropic-chat-model.js.map +1 -0
- package/dist/lib/llm/providers/gemini-chat-model.d.ts +30 -0
- package/dist/lib/llm/providers/gemini-chat-model.d.ts.map +1 -0
- package/dist/lib/llm/providers/gemini-chat-model.js +300 -0
- package/dist/lib/llm/providers/gemini-chat-model.js.map +1 -0
- package/dist/lib/llm/providers/gemini-embeddings.d.ts +14 -0
- package/dist/lib/llm/providers/gemini-embeddings.d.ts.map +1 -0
- package/dist/lib/llm/providers/gemini-embeddings.js +20 -0
- package/dist/lib/llm/providers/gemini-embeddings.js.map +1 -0
- package/dist/lib/llm/providers/openai-chat-model.d.ts +39 -0
- package/dist/lib/llm/providers/openai-chat-model.d.ts.map +1 -0
- package/dist/lib/llm/providers/openai-chat-model.js +397 -0
- package/dist/lib/llm/providers/openai-chat-model.js.map +1 -0
- package/dist/lib/llm/providers/openai-embeddings.d.ts +17 -0
- package/dist/lib/llm/providers/openai-embeddings.d.ts.map +1 -0
- package/dist/lib/llm/providers/openai-embeddings.js +35 -0
- package/dist/lib/llm/providers/openai-embeddings.js.map +1 -0
- package/dist/lib/llm/types.d.ts +2 -2
- package/dist/lib/llm/types.js +1 -1
- package/dist/lib/logger.d.ts +7 -0
- package/dist/lib/logger.d.ts.map +1 -1
- package/dist/lib/logger.js +42 -4
- package/dist/lib/logger.js.map +1 -1
- package/dist/lib/mcp/index.d.ts +3 -3
- package/dist/lib/mcp/index.js +2 -2
- package/dist/lib/mcp/mcp-client.d.ts +3 -2
- package/dist/lib/mcp/mcp-client.d.ts.map +1 -1
- package/dist/lib/mcp/mcp-client.js +10 -5
- package/dist/lib/mcp/mcp-client.js.map +1 -1
- package/dist/lib/mcp/types.d.ts +26 -25
- package/dist/lib/mcp/types.d.ts.map +1 -1
- package/dist/lib/mcp/types.js +12 -4
- package/dist/lib/mcp/types.js.map +1 -1
- package/dist/lib/memory/conversation-store.d.ts +2 -2
- package/dist/lib/memory/conversation-store.d.ts.map +1 -1
- package/dist/lib/memory/conversation-store.js +1 -1
- package/dist/lib/memory/index.d.ts +3 -2
- package/dist/lib/memory/index.d.ts.map +1 -1
- package/dist/lib/memory/index.js +3 -2
- package/dist/lib/memory/index.js.map +1 -1
- package/dist/lib/memory/memory-manager.d.ts +10 -0
- package/dist/lib/memory/memory-manager.d.ts.map +1 -0
- package/dist/lib/memory/memory-manager.js +43 -0
- package/dist/lib/memory/memory-manager.js.map +1 -0
- package/dist/lib/memory/types.d.ts +1 -1
- package/dist/lib/memory/types.d.ts.map +1 -1
- package/dist/lib/orchestrator.d.ts +72 -18
- package/dist/lib/orchestrator.d.ts.map +1 -1
- package/dist/lib/orchestrator.js +341 -56
- package/dist/lib/orchestrator.js.map +1 -1
- package/dist/lib/sandbox/cdp-client.d.ts +14 -0
- package/dist/lib/sandbox/cdp-client.d.ts.map +1 -0
- package/dist/lib/sandbox/cdp-client.js +113 -0
- package/dist/lib/sandbox/cdp-client.js.map +1 -0
- package/dist/lib/sandbox/html-to-markdown.d.ts +10 -0
- package/dist/lib/sandbox/html-to-markdown.d.ts.map +1 -0
- package/dist/lib/sandbox/html-to-markdown.js +121 -0
- package/dist/lib/sandbox/html-to-markdown.js.map +1 -0
- package/dist/lib/sandbox/index.d.ts +12 -0
- package/dist/lib/sandbox/index.d.ts.map +1 -0
- package/dist/lib/sandbox/index.js +10 -0
- package/dist/lib/sandbox/index.js.map +1 -0
- package/dist/lib/sandbox/page-readiness.d.ts +37 -0
- package/dist/lib/sandbox/page-readiness.d.ts.map +1 -0
- package/dist/lib/sandbox/page-readiness.js +235 -0
- package/dist/lib/sandbox/page-readiness.js.map +1 -0
- package/dist/lib/sandbox/sandbox-browser.d.ts +4 -0
- package/dist/lib/sandbox/sandbox-browser.d.ts.map +1 -0
- package/dist/lib/sandbox/sandbox-browser.js +303 -0
- package/dist/lib/sandbox/sandbox-browser.js.map +1 -0
- package/dist/lib/sandbox/sandbox-exec.d.ts +5 -0
- package/dist/lib/sandbox/sandbox-exec.d.ts.map +1 -0
- package/dist/lib/sandbox/sandbox-exec.js +35 -0
- package/dist/lib/sandbox/sandbox-exec.js.map +1 -0
- package/dist/lib/sandbox/sandbox-file.d.ts +4 -0
- package/dist/lib/sandbox/sandbox-file.d.ts.map +1 -0
- package/dist/lib/sandbox/sandbox-file.js +168 -0
- package/dist/lib/sandbox/sandbox-file.js.map +1 -0
- package/dist/lib/sandbox/sandbox-shell.d.ts +4 -0
- package/dist/lib/sandbox/sandbox-shell.d.ts.map +1 -0
- package/dist/lib/sandbox/sandbox-shell.js +93 -0
- package/dist/lib/sandbox/sandbox-shell.js.map +1 -0
- package/dist/lib/sandbox/sandbox-web.d.ts +5 -0
- package/dist/lib/sandbox/sandbox-web.d.ts.map +1 -0
- package/dist/lib/sandbox/sandbox-web.js +226 -0
- package/dist/lib/sandbox/sandbox-web.js.map +1 -0
- package/dist/lib/sandbox/types.d.ts +30 -0
- package/dist/lib/sandbox/types.d.ts.map +1 -0
- package/dist/lib/sandbox/types.js +8 -0
- package/dist/lib/sandbox/types.js.map +1 -0
- package/dist/lib/sandbox/vision-browser.d.ts +4 -0
- package/dist/lib/sandbox/vision-browser.d.ts.map +1 -0
- package/dist/lib/sandbox/vision-browser.js +289 -0
- package/dist/lib/sandbox/vision-browser.js.map +1 -0
- package/dist/lib/sandbox/vm-executor.d.ts +12 -0
- package/dist/lib/sandbox/vm-executor.d.ts.map +1 -0
- package/dist/lib/sandbox/vm-executor.js +101 -0
- package/dist/lib/sandbox/vm-executor.js.map +1 -0
- package/dist/lib/skills/index.d.ts +4 -0
- package/dist/lib/skills/index.d.ts.map +1 -0
- package/dist/lib/skills/index.js +3 -0
- package/dist/lib/skills/index.js.map +1 -0
- package/dist/lib/skills/skill-loader.d.ts +21 -0
- package/dist/lib/skills/skill-loader.d.ts.map +1 -0
- package/dist/lib/skills/skill-loader.js +116 -0
- package/dist/lib/skills/skill-loader.js.map +1 -0
- package/dist/lib/skills/types.d.ts +17 -0
- package/dist/lib/skills/types.d.ts.map +1 -0
- package/dist/lib/skills/types.js +6 -0
- package/dist/lib/skills/types.js.map +1 -0
- package/dist/lib/tasks/index.d.ts +4 -0
- package/dist/lib/tasks/index.d.ts.map +1 -0
- package/dist/lib/tasks/index.js +4 -0
- package/dist/lib/tasks/index.js.map +1 -0
- package/dist/lib/tasks/task-manager.d.ts +27 -0
- package/dist/lib/tasks/task-manager.d.ts.map +1 -0
- package/dist/lib/tasks/task-manager.js +200 -0
- package/dist/lib/tasks/task-manager.js.map +1 -0
- package/dist/lib/tasks/task-store.d.ts +20 -0
- package/dist/lib/tasks/task-store.d.ts.map +1 -0
- package/dist/lib/tasks/task-store.js +102 -0
- package/dist/lib/tasks/task-store.js.map +1 -0
- package/dist/lib/tasks/types.d.ts +56 -0
- package/dist/lib/tasks/types.d.ts.map +1 -0
- package/dist/lib/tasks/types.js +2 -0
- package/dist/lib/tasks/types.js.map +1 -0
- package/dist/lib/templates/resource-templates.d.ts +6 -0
- package/dist/lib/templates/resource-templates.d.ts.map +1 -0
- package/dist/lib/templates/resource-templates.js +146 -0
- package/dist/lib/templates/resource-templates.js.map +1 -0
- package/dist/lib/tools/agent-tool-wrapper.d.ts +5 -5
- package/dist/lib/tools/agent-tool-wrapper.js +3 -3
- package/dist/lib/tools/agent-tool-wrapper.js.map +1 -1
- package/dist/lib/tools/built-in/ask-user.tool.d.ts +1 -1
- package/dist/lib/tools/built-in/ask-user.tool.d.ts.map +1 -1
- package/dist/lib/tools/built-in/ask-user.tool.js +2 -2
- package/dist/lib/tools/built-in/ask-user.tool.js.map +1 -1
- package/dist/lib/tools/built-in/index.d.ts +9 -2
- package/dist/lib/tools/built-in/index.d.ts.map +1 -1
- package/dist/lib/tools/built-in/index.js +9 -2
- package/dist/lib/tools/built-in/index.js.map +1 -1
- package/dist/lib/tools/built-in/integration-tools.d.ts +4 -0
- package/dist/lib/tools/built-in/integration-tools.d.ts.map +1 -0
- package/dist/lib/tools/built-in/integration-tools.js +47 -0
- package/dist/lib/tools/built-in/integration-tools.js.map +1 -0
- package/dist/lib/tools/built-in/knowledge-entity-lookup.tool.d.ts +9 -0
- package/dist/lib/tools/built-in/knowledge-entity-lookup.tool.d.ts.map +1 -0
- package/dist/lib/tools/built-in/knowledge-entity-lookup.tool.js +108 -0
- package/dist/lib/tools/built-in/knowledge-entity-lookup.tool.js.map +1 -0
- package/dist/lib/tools/built-in/knowledge-graph-schema.tool.d.ts +9 -0
- package/dist/lib/tools/built-in/knowledge-graph-schema.tool.d.ts.map +1 -0
- package/dist/lib/tools/built-in/knowledge-graph-schema.tool.js +96 -0
- package/dist/lib/tools/built-in/knowledge-graph-schema.tool.js.map +1 -0
- package/dist/lib/tools/built-in/knowledge-search.tool.d.ts +2 -2
- package/dist/lib/tools/built-in/knowledge-search.tool.d.ts.map +1 -1
- package/dist/lib/tools/built-in/knowledge-search.tool.js +1 -1
- package/dist/lib/tools/built-in/knowledge-search.tool.js.map +1 -1
- package/dist/lib/tools/built-in/knowledge-sql.tool.d.ts +7 -0
- package/dist/lib/tools/built-in/knowledge-sql.tool.d.ts.map +1 -0
- package/dist/lib/tools/built-in/knowledge-sql.tool.js +128 -0
- package/dist/lib/tools/built-in/knowledge-sql.tool.js.map +1 -0
- package/dist/lib/tools/built-in/knowledge-tools-factory.d.ts +17 -0
- package/dist/lib/tools/built-in/knowledge-tools-factory.d.ts.map +1 -0
- package/dist/lib/tools/built-in/knowledge-tools-factory.js +54 -0
- package/dist/lib/tools/built-in/knowledge-tools-factory.js.map +1 -0
- package/dist/lib/tools/built-in/knowledge-traverse.tool.d.ts +9 -0
- package/dist/lib/tools/built-in/knowledge-traverse.tool.d.ts.map +1 -0
- package/dist/lib/tools/built-in/knowledge-traverse.tool.js +91 -0
- package/dist/lib/tools/built-in/knowledge-traverse.tool.js.map +1 -0
- package/dist/lib/tools/built-in/memory-save.tool.d.ts +4 -0
- package/dist/lib/tools/built-in/memory-save.tool.d.ts.map +1 -0
- package/dist/lib/tools/built-in/memory-save.tool.js +21 -0
- package/dist/lib/tools/built-in/memory-save.tool.js.map +1 -0
- package/dist/lib/tools/built-in/query-validators.d.ts +18 -0
- package/dist/lib/tools/built-in/query-validators.d.ts.map +1 -0
- package/dist/lib/tools/built-in/query-validators.js +91 -0
- package/dist/lib/tools/built-in/query-validators.js.map +1 -0
- package/dist/lib/tools/index.d.ts +4 -4
- package/dist/lib/tools/index.js +4 -4
- package/dist/lib/tools/tool-discovery.d.ts +11 -33
- package/dist/lib/tools/tool-discovery.d.ts.map +1 -1
- package/dist/lib/tools/tool-discovery.js +16 -43
- package/dist/lib/tools/tool-discovery.js.map +1 -1
- package/dist/lib/tools/tool-registry.d.ts +10 -18
- package/dist/lib/tools/tool-registry.d.ts.map +1 -1
- package/dist/lib/tools/tool-registry.js +37 -23
- package/dist/lib/tools/tool-registry.js.map +1 -1
- package/dist/lib/tools/workspace/workspace-tools.d.ts +61 -0
- package/dist/lib/tools/workspace/workspace-tools.d.ts.map +1 -0
- package/dist/lib/tools/workspace/workspace-tools.js +179 -0
- package/dist/lib/tools/workspace/workspace-tools.js.map +1 -0
- package/dist/lib/triggers/cron-trigger.d.ts +12 -0
- package/dist/lib/triggers/cron-trigger.d.ts.map +1 -0
- package/dist/lib/triggers/cron-trigger.js +45 -0
- package/dist/lib/triggers/cron-trigger.js.map +1 -0
- package/dist/lib/triggers/index.d.ts +6 -0
- package/dist/lib/triggers/index.d.ts.map +1 -0
- package/dist/lib/triggers/index.js +5 -0
- package/dist/lib/triggers/index.js.map +1 -0
- package/dist/lib/triggers/trigger-manager.d.ts +12 -0
- package/dist/lib/triggers/trigger-manager.d.ts.map +1 -0
- package/dist/lib/triggers/trigger-manager.js +77 -0
- package/dist/lib/triggers/trigger-manager.js.map +1 -0
- package/dist/lib/triggers/types.d.ts +57 -0
- package/dist/lib/triggers/types.d.ts.map +1 -0
- package/dist/lib/triggers/types.js +16 -0
- package/dist/lib/triggers/types.js.map +1 -0
- package/dist/lib/triggers/webhook-trigger.d.ts +12 -0
- package/dist/lib/triggers/webhook-trigger.d.ts.map +1 -0
- package/dist/lib/triggers/webhook-trigger.js +34 -0
- package/dist/lib/triggers/webhook-trigger.js.map +1 -0
- package/dist/lib/types/llm-types.d.ts +72 -0
- package/dist/lib/types/llm-types.d.ts.map +1 -0
- package/dist/lib/types/llm-types.js +72 -0
- package/dist/lib/types/llm-types.js.map +1 -0
- package/dist/lib/types/text-splitters.d.ts +27 -0
- package/dist/lib/types/text-splitters.d.ts.map +1 -0
- package/dist/lib/types/text-splitters.js +114 -0
- package/dist/lib/types/text-splitters.js.map +1 -0
- package/dist/lib/types/tool-factory.d.ts +9 -0
- package/dist/lib/types/tool-factory.d.ts.map +1 -0
- package/dist/lib/types/tool-factory.js +12 -0
- package/dist/lib/types/tool-factory.js.map +1 -0
- package/dist/lib/utils/env-substitution.d.ts +6 -0
- package/dist/lib/utils/env-substitution.d.ts.map +1 -0
- package/dist/lib/utils/env-substitution.js +15 -0
- package/dist/lib/utils/env-substitution.js.map +1 -0
- package/dist/lib/utils/file-utils.d.ts +11 -0
- package/dist/lib/utils/file-utils.d.ts.map +1 -0
- package/dist/lib/utils/file-utils.js +86 -0
- package/dist/lib/utils/file-utils.js.map +1 -0
- package/dist/lib/workflows/index.d.ts +6 -6
- package/dist/lib/workflows/index.d.ts.map +1 -1
- package/dist/lib/workflows/index.js +5 -5
- package/dist/lib/workflows/index.js.map +1 -1
- package/dist/lib/workflows/interrupt-manager.d.ts +1 -1
- package/dist/lib/workflows/interrupt-manager.js +1 -1
- package/dist/lib/workflows/react-workflow-executor.d.ts +26 -0
- package/dist/lib/workflows/react-workflow-executor.d.ts.map +1 -0
- package/dist/lib/workflows/react-workflow-executor.js +333 -0
- package/dist/lib/workflows/react-workflow-executor.js.map +1 -0
- package/dist/lib/workflows/types.d.ts +106 -107
- package/dist/lib/workflows/types.d.ts.map +1 -1
- package/dist/lib/workflows/types.js +5 -5
- package/dist/lib/workflows/types.js.map +1 -1
- package/dist/lib/workflows/workflow-executor.d.ts +3 -3
- package/dist/lib/workflows/workflow-executor.js +2 -2
- package/dist/lib/workflows/workflow-executor.js.map +1 -1
- package/dist/lib/workflows/workflow-loader.d.ts +4 -1
- package/dist/lib/workflows/workflow-loader.d.ts.map +1 -1
- package/dist/lib/workflows/workflow-loader.js +20 -4
- package/dist/lib/workflows/workflow-loader.js.map +1 -1
- package/dist/public/chat.html +114 -0
- package/dist/public/index.html +189 -0
- package/dist/public/src/components/AgentComposer.js +807 -0
- package/dist/public/src/components/AgentsView.js +1021 -344
- package/dist/public/src/components/AppRoot.js +150 -5
- package/dist/public/src/components/GraphView.js +420 -0
- package/dist/public/src/components/IdeView.js +625 -14
- package/dist/public/src/components/KnowledgeView.js +443 -66
- package/dist/public/src/components/MonitorView.js +526 -0
- package/dist/public/src/components/NavBar.js +3 -0
- package/dist/public/src/components/SkillsView.js +137 -0
- package/dist/public/src/components/StandaloneChat.js +889 -0
- package/dist/public/src/components/WorkflowsView.js +454 -129
- package/dist/public/src/services/ApiService.js +170 -25
- package/dist/public/src/services/SessionStore.js +83 -0
- package/dist/public/src/store.js +3 -4
- package/dist/public/src/utils/markdown.js +14 -0
- package/dist/src/cli/commands/init.js +2 -2
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/cli/commands/start.d.ts +0 -1
- package/dist/src/cli/commands/start.d.ts.map +1 -1
- package/dist/src/cli/commands/start.js +23 -14
- package/dist/src/cli/commands/start.js.map +1 -1
- package/dist/src/cli/index.js +8 -5
- package/dist/src/cli/index.js.map +1 -1
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +23 -9
- package/dist/src/index.js.map +1 -1
- package/dist/src/middleware/auth.d.ts +3 -0
- package/dist/src/middleware/auth.d.ts.map +1 -0
- package/dist/src/middleware/auth.js +129 -0
- package/dist/src/middleware/auth.js.map +1 -0
- package/dist/src/middleware/rate-limit.d.ts +8 -0
- package/dist/src/middleware/rate-limit.d.ts.map +1 -0
- package/dist/src/middleware/rate-limit.js +21 -0
- package/dist/src/middleware/rate-limit.js.map +1 -0
- package/dist/src/routes/agents.route.d.ts.map +1 -1
- package/dist/src/routes/agents.route.js +167 -12
- package/dist/src/routes/agents.route.js.map +1 -1
- package/dist/src/routes/chat.route.d.ts +3 -0
- package/dist/src/routes/chat.route.d.ts.map +1 -0
- package/dist/src/routes/chat.route.js +155 -0
- package/dist/src/routes/chat.route.js.map +1 -0
- package/dist/src/routes/files.route.d.ts.map +1 -1
- package/dist/src/routes/files.route.js +163 -87
- package/dist/src/routes/files.route.js.map +1 -1
- package/dist/src/routes/functions.route.js +1 -1
- package/dist/src/routes/graph.route.d.ts +3 -0
- package/dist/src/routes/graph.route.d.ts.map +1 -0
- package/dist/src/routes/graph.route.js +173 -0
- package/dist/src/routes/graph.route.js.map +1 -0
- package/dist/src/routes/knowledge.route.d.ts.map +1 -1
- package/dist/src/routes/knowledge.route.js +172 -69
- package/dist/src/routes/knowledge.route.js.map +1 -1
- package/dist/src/routes/llm.route.d.ts.map +1 -1
- package/dist/src/routes/llm.route.js +85 -9
- package/dist/src/routes/llm.route.js.map +1 -1
- package/dist/src/routes/mcp.route.js +1 -1
- package/dist/src/routes/skills.route.d.ts +3 -0
- package/dist/src/routes/skills.route.d.ts.map +1 -0
- package/dist/src/routes/skills.route.js +23 -0
- package/dist/src/routes/skills.route.js.map +1 -0
- package/dist/src/routes/tasks.route.d.ts +3 -0
- package/dist/src/routes/tasks.route.d.ts.map +1 -0
- package/dist/src/routes/tasks.route.js +149 -0
- package/dist/src/routes/tasks.route.js.map +1 -0
- package/dist/src/routes/vnc.route.d.ts +3 -0
- package/dist/src/routes/vnc.route.d.ts.map +1 -0
- package/dist/src/routes/vnc.route.js +49 -0
- package/dist/src/routes/vnc.route.js.map +1 -0
- package/dist/src/routes/workflows.route.d.ts.map +1 -1
- package/dist/src/routes/workflows.route.js +9 -1
- package/dist/src/routes/workflows.route.js.map +1 -1
- package/dist/src/server.d.ts +1 -1
- package/dist/src/server.d.ts.map +1 -1
- package/dist/src/server.js +26 -9
- package/dist/src/server.js.map +1 -1
- package/dist/templates/.env.example +4 -19
- package/dist/templates/Demo.md +152 -0
- package/dist/templates/README.md +28 -11
- package/dist/templates/agents/architect.agent.yaml +57 -0
- package/dist/templates/agents/chatbot.agent.yaml +55 -0
- package/dist/templates/agents/corporate.agent.yaml +65 -0
- package/dist/templates/agents/investment-analyst.agent.yaml +80 -0
- package/dist/templates/agents/music-librarian.agent.yaml +70 -0
- package/dist/templates/agents/network-security.agent.yaml +82 -0
- package/dist/templates/agents/transport-security.agent.yaml +70 -0
- package/dist/templates/agents/web-engineer.agent.yaml +99 -0
- package/dist/templates/agents/web-pilot.agent.yaml +58 -0
- package/dist/templates/knowledge/music-store/LICENSE.md +11 -0
- package/dist/templates/knowledge/music-store/musicstore.sqlite +0 -0
- package/dist/templates/knowledge/music-store/tables.png +0 -0
- package/dist/templates/knowledge/music-store.knowledge.yaml +138 -0
- package/dist/templates/knowledge/org-chart/personnel.csv +21 -0
- package/dist/templates/knowledge/org-chart.knowledge.yaml +53 -0
- package/dist/templates/knowledge/pet-store/pet-store.db +0 -0
- package/dist/templates/knowledge/pet-store.knowledge.yaml +81 -0
- package/dist/templates/knowledge/security-incidents/incidents.json +55935 -0
- package/dist/templates/knowledge/security-incidents.knowledge.yaml +46 -0
- package/dist/templates/knowledge/transcripts.knowledge.yaml +29 -0
- package/dist/templates/knowledge/transport-ot/systems.csv +117 -0
- package/dist/templates/knowledge/transport-ot.knowledge.yaml +55 -0
- package/dist/templates/knowledge/web-docs.knowledge.yaml +20 -0
- package/dist/templates/llm.json +7 -30
- package/dist/templates/mcp.json +10 -4
- package/dist/templates/skills/orcha-builder/SKILL.md +219 -0
- package/dist/templates/skills/pii-guard/SKILL.md +22 -0
- package/dist/templates/skills/sandbox/SKILL.md +40 -0
- package/dist/templates/skills/web-pilot/SKILL.md +51 -0
- package/dist/templates/workflows/example.workflow.yaml +25 -30
- package/dist/templates/workflows/react-example.workflow.yaml +53 -0
- package/package.json +22 -20
- package/dist/lib/knowledge/graph-rag/community-detector.d.ts +0 -16
- package/dist/lib/knowledge/graph-rag/community-detector.d.ts.map +0 -1
- package/dist/lib/knowledge/graph-rag/community-detector.js +0 -81
- package/dist/lib/knowledge/graph-rag/community-detector.js.map +0 -1
- package/dist/lib/knowledge/graph-rag/community-summarizer.d.ts +0 -17
- package/dist/lib/knowledge/graph-rag/community-summarizer.d.ts.map +0 -1
- package/dist/lib/knowledge/graph-rag/community-summarizer.js +0 -87
- package/dist/lib/knowledge/graph-rag/community-summarizer.js.map +0 -1
- package/dist/lib/knowledge/graph-rag/entity-extractor.d.ts +0 -36
- package/dist/lib/knowledge/graph-rag/entity-extractor.d.ts.map +0 -1
- package/dist/lib/knowledge/graph-rag/entity-extractor.js +0 -192
- package/dist/lib/knowledge/graph-rag/entity-extractor.js.map +0 -1
- package/dist/lib/knowledge/graph-rag/extraction-cache.d.ts +0 -30
- package/dist/lib/knowledge/graph-rag/extraction-cache.d.ts.map +0 -1
- package/dist/lib/knowledge/graph-rag/extraction-cache.js +0 -88
- package/dist/lib/knowledge/graph-rag/extraction-cache.js.map +0 -1
- package/dist/lib/knowledge/graph-rag/global-search.d.ts +0 -19
- package/dist/lib/knowledge/graph-rag/global-search.d.ts.map +0 -1
- package/dist/lib/knowledge/graph-rag/global-search.js +0 -96
- package/dist/lib/knowledge/graph-rag/global-search.js.map +0 -1
- package/dist/lib/knowledge/graph-rag/graph-rag-factory.d.ts +0 -24
- package/dist/lib/knowledge/graph-rag/graph-rag-factory.d.ts.map +0 -1
- package/dist/lib/knowledge/graph-rag/graph-rag-factory.js +0 -239
- package/dist/lib/knowledge/graph-rag/graph-rag-factory.js.map +0 -1
- package/dist/lib/knowledge/graph-rag/index.d.ts +0 -14
- package/dist/lib/knowledge/graph-rag/index.d.ts.map +0 -1
- package/dist/lib/knowledge/graph-rag/index.js +0 -12
- package/dist/lib/knowledge/graph-rag/index.js.map +0 -1
- package/dist/lib/knowledge/graph-rag/local-search.d.ts +0 -20
- package/dist/lib/knowledge/graph-rag/local-search.d.ts.map +0 -1
- package/dist/lib/knowledge/graph-rag/local-search.js +0 -110
- package/dist/lib/knowledge/graph-rag/local-search.js.map +0 -1
- package/dist/lib/knowledge/graph-rag/memory-graph-store.d.ts +0 -31
- package/dist/lib/knowledge/graph-rag/memory-graph-store.d.ts.map +0 -1
- package/dist/lib/knowledge/graph-rag/memory-graph-store.js +0 -165
- package/dist/lib/knowledge/graph-rag/memory-graph-store.js.map +0 -1
- package/dist/lib/knowledge/graph-rag/neo4j-graph-store.d.ts +0 -38
- package/dist/lib/knowledge/graph-rag/neo4j-graph-store.d.ts.map +0 -1
- package/dist/lib/knowledge/graph-rag/neo4j-graph-store.js +0 -190
- package/dist/lib/knowledge/graph-rag/neo4j-graph-store.js.map +0 -1
- package/dist/lib/knowledge/graph-rag/search-mode-detector.d.ts +0 -11
- package/dist/lib/knowledge/graph-rag/search-mode-detector.d.ts.map +0 -1
- package/dist/lib/knowledge/graph-rag/search-mode-detector.js +0 -50
- package/dist/lib/knowledge/graph-rag/search-mode-detector.js.map +0 -1
- package/dist/lib/knowledge/graph-rag/types.d.ts +0 -368
- package/dist/lib/knowledge/graph-rag/types.d.ts.map +0 -1
- package/dist/lib/knowledge/graph-rag/types.js +0 -48
- package/dist/lib/knowledge/graph-rag/types.js.map +0 -1
- package/dist/lib/knowledge/knowledge-store-factory.d.ts +0 -16
- package/dist/lib/knowledge/knowledge-store-factory.d.ts.map +0 -1
- package/dist/lib/knowledge/knowledge-store-factory.js +0 -376
- package/dist/lib/knowledge/knowledge-store-factory.js.map +0 -1
- package/dist/lib/knowledge/knowledge-store-manager.d.ts +0 -18
- package/dist/lib/knowledge/knowledge-store-manager.d.ts.map +0 -1
- package/dist/lib/knowledge/knowledge-store-manager.js +0 -98
- package/dist/lib/knowledge/knowledge-store-manager.js.map +0 -1
- package/dist/lib/knowledge/loaders/s3-loader.d.ts +0 -17
- package/dist/lib/knowledge/loaders/s3-loader.d.ts.map +0 -1
- package/dist/lib/knowledge/loaders/s3-loader.js +0 -185
- package/dist/lib/knowledge/loaders/s3-loader.js.map +0 -1
- package/dist/lib/workflows/langgraph-executor.d.ts +0 -51
- package/dist/lib/workflows/langgraph-executor.d.ts.map +0 -1
- package/dist/lib/workflows/langgraph-executor.js +0 -297
- package/dist/lib/workflows/langgraph-executor.js.map +0 -1
- package/dist/templates/agents/call-center-analyst-simple.agent.yaml +0 -36
- package/dist/templates/agents/math.agent.yaml +0 -28
- package/dist/templates/agents/sentiment-structured.agent.yaml +0 -42
- package/dist/templates/knowledge/example.knowledge.yaml +0 -28
- package/dist/templates/llm.md +0 -1195
- package/dist/templates/workflows/langgraph-example.workflow.yaml +0 -84
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
import { Component } from '../utils/Component.js';
|
|
3
3
|
import { api } from '../services/ApiService.js';
|
|
4
|
+
import { sessionStore } from '../services/SessionStore.js';
|
|
4
5
|
import { store } from '../store.js';
|
|
5
6
|
import { markdownRenderer } from '../utils/markdown.js';
|
|
6
7
|
|
|
@@ -8,25 +9,118 @@ export class AgentsView extends Component {
|
|
|
8
9
|
constructor() {
|
|
9
10
|
super();
|
|
10
11
|
this.isLoading = false;
|
|
12
|
+
this.currentAbortController = null;
|
|
13
|
+
this.streamStartTime = null;
|
|
14
|
+
this.streamTimerInterval = null;
|
|
15
|
+
this.streamUsageData = null;
|
|
16
|
+
this.pendingAttachments = [];
|
|
11
17
|
}
|
|
12
18
|
|
|
13
19
|
async connectedCallback() {
|
|
14
20
|
super.connectedCallback();
|
|
15
21
|
await Promise.all([this.loadAgents(), this.loadLLMs()]);
|
|
22
|
+
this.restoreActiveSession();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
disconnectedCallback() {
|
|
26
|
+
this.stopStreamTimer();
|
|
27
|
+
if (this.currentAbortController) {
|
|
28
|
+
this.currentAbortController.abort();
|
|
29
|
+
this.currentAbortController = null;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
formatElapsedTime(ms) {
|
|
34
|
+
if (ms < 1000) return `${ms}ms`;
|
|
35
|
+
const seconds = ms / 1000;
|
|
36
|
+
if (seconds < 60) return `${seconds.toFixed(1)}s`;
|
|
37
|
+
const minutes = Math.floor(seconds / 60);
|
|
38
|
+
const remainingSeconds = (seconds % 60).toFixed(0);
|
|
39
|
+
return `${minutes}m ${remainingSeconds}s`;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
estimateTokens(text) {
|
|
43
|
+
return Math.round((text || '').length / 4);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
cancelCurrentStream() {
|
|
47
|
+
if (this.currentAbortController) {
|
|
48
|
+
this.currentAbortController.abort();
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
startStreamTimer(responseId) {
|
|
53
|
+
this.streamStartTime = Date.now();
|
|
54
|
+
this.streamTimerInterval = setInterval(() => {
|
|
55
|
+
const elapsed = Date.now() - this.streamStartTime;
|
|
56
|
+
const bubble = this.querySelector(`#${responseId}`);
|
|
57
|
+
if (!bubble) return;
|
|
58
|
+
const timerEl = bubble.parentElement.querySelector('.stream-elapsed');
|
|
59
|
+
if (timerEl) {
|
|
60
|
+
timerEl.textContent = this.formatElapsedTime(elapsed);
|
|
61
|
+
}
|
|
62
|
+
}, 100);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
stopStreamTimer(responseId, inputMessage, finalContent, wasCancelled) {
|
|
66
|
+
if (this.streamTimerInterval) {
|
|
67
|
+
clearInterval(this.streamTimerInterval);
|
|
68
|
+
this.streamTimerInterval = null;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const elapsed = this.streamStartTime ? Date.now() - this.streamStartTime : 0;
|
|
72
|
+
this.streamStartTime = null;
|
|
73
|
+
|
|
74
|
+
const bubble = this.querySelector(`#${responseId}`);
|
|
75
|
+
if (!bubble) return;
|
|
76
|
+
|
|
77
|
+
const wrapper = bubble.parentElement;
|
|
78
|
+
const statusBar = wrapper.querySelector('.stream-status-bar');
|
|
79
|
+
const statsBar = wrapper.querySelector('.stream-stats-bar');
|
|
80
|
+
|
|
81
|
+
if (statusBar) statusBar.classList.add('hidden');
|
|
82
|
+
|
|
83
|
+
if (statsBar) {
|
|
84
|
+
const elapsedEl = statsBar.querySelector('.stats-elapsed');
|
|
85
|
+
const inputTokensEl = statsBar.querySelector('.stats-input-tokens');
|
|
86
|
+
const outputTokensEl = statsBar.querySelector('.stats-output-tokens');
|
|
87
|
+
const tpsEl = statsBar.querySelector('.stats-tps');
|
|
88
|
+
|
|
89
|
+
const usage = this.streamUsageData;
|
|
90
|
+
const hasRealUsage = usage && (usage.input_tokens > 0 || usage.output_tokens > 0);
|
|
91
|
+
|
|
92
|
+
const inputTokens = hasRealUsage ? usage.input_tokens : this.estimateTokens(inputMessage);
|
|
93
|
+
const outputTokens = hasRealUsage ? usage.output_tokens : this.estimateTokens(finalContent);
|
|
94
|
+
const prefix = hasRealUsage ? '' : '~';
|
|
95
|
+
|
|
96
|
+
if (elapsedEl) elapsedEl.textContent = this.formatElapsedTime(elapsed);
|
|
97
|
+
if (inputTokensEl) inputTokensEl.textContent = `${prefix}${inputTokens} input`;
|
|
98
|
+
if (outputTokensEl) outputTokensEl.textContent = `${prefix}${outputTokens} output`;
|
|
99
|
+
|
|
100
|
+
if (tpsEl) {
|
|
101
|
+
const seconds = elapsed / 1000;
|
|
102
|
+
const tps = seconds > 0 ? (outputTokens / seconds).toFixed(1) : 0;
|
|
103
|
+
tpsEl.textContent = `${prefix}${tps} tok/s`;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
this.streamUsageData = null;
|
|
107
|
+
|
|
108
|
+
if (wasCancelled) {
|
|
109
|
+
const cancelBadge = document.createElement('span');
|
|
110
|
+
cancelBadge.className = 'text-xs text-amber-400 font-medium ml-2';
|
|
111
|
+
cancelBadge.textContent = 'Cancelled';
|
|
112
|
+
statsBar.appendChild(cancelBadge);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
statsBar.classList.remove('hidden');
|
|
116
|
+
}
|
|
16
117
|
}
|
|
17
118
|
|
|
18
119
|
async loadAgents() {
|
|
19
120
|
try {
|
|
20
121
|
const agents = await api.getAgents();
|
|
122
|
+
agents.sort((a, b) => (a.name || '').localeCompare(b.name || ''));
|
|
21
123
|
store.set('agents', agents);
|
|
22
|
-
|
|
23
|
-
if (agents.length > 0 && !store.get('selectedAgent') && !store.get('selectedLlm')) {
|
|
24
|
-
store.set('selectedAgent', agents[agents.length - 1]);
|
|
25
|
-
store.set('selectionType', 'agent');
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
this.renderAgentDropdown();
|
|
29
|
-
this.updateSelectedAgentUI();
|
|
30
124
|
} catch (e) {
|
|
31
125
|
console.error('Failed to load agents', e);
|
|
32
126
|
}
|
|
@@ -36,152 +130,491 @@ export class AgentsView extends Component {
|
|
|
36
130
|
try {
|
|
37
131
|
const llms = await api.getLLMs();
|
|
38
132
|
store.set('llms', llms);
|
|
39
|
-
this.renderAgentDropdown();
|
|
40
133
|
} catch (e) {
|
|
41
134
|
console.error('Failed to load LLMs', e);
|
|
42
135
|
}
|
|
43
136
|
}
|
|
44
137
|
|
|
45
|
-
|
|
46
|
-
|
|
138
|
+
// --- Sidebar toggle (mobile) ---
|
|
139
|
+
|
|
140
|
+
_isMobile() {
|
|
141
|
+
return !window.matchMedia('(min-width: 768px)').matches;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
toggleSidebar(show) {
|
|
145
|
+
const sidebar = this.querySelector('#sidebar');
|
|
146
|
+
const backdrop = this.querySelector('#sidebarBackdrop');
|
|
147
|
+
if (!sidebar || !backdrop) return;
|
|
148
|
+
|
|
149
|
+
if (show) {
|
|
150
|
+
sidebar.classList.remove('hidden');
|
|
151
|
+
sidebar.classList.add('flex', 'sidebar-open');
|
|
152
|
+
backdrop.classList.remove('hidden');
|
|
153
|
+
} else {
|
|
154
|
+
sidebar.classList.add('hidden');
|
|
155
|
+
sidebar.classList.remove('flex', 'sidebar-open');
|
|
156
|
+
backdrop.classList.add('hidden');
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// --- Session management ---
|
|
161
|
+
|
|
162
|
+
restoreActiveSession() {
|
|
163
|
+
const activeId = sessionStore.getActiveId();
|
|
164
|
+
if (activeId && sessionStore.get(activeId)) {
|
|
165
|
+
this.switchToSession(activeId);
|
|
166
|
+
} else {
|
|
167
|
+
this.showEmptyState();
|
|
168
|
+
}
|
|
169
|
+
this.renderSessionList();
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
renderSessionList() {
|
|
173
|
+
const list = this.querySelector('#sessionList');
|
|
174
|
+
if (!list) return;
|
|
175
|
+
|
|
176
|
+
const sessions = sessionStore.getAll();
|
|
177
|
+
const activeId = sessionStore.getActiveId();
|
|
178
|
+
|
|
179
|
+
if (sessions.length === 0) {
|
|
180
|
+
list.innerHTML = '<div class="text-gray-500 text-sm text-center py-8">No conversations yet</div>';
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
list.innerHTML = sessions.map(s => {
|
|
185
|
+
const isActive = s.id === activeId;
|
|
186
|
+
const isAgent = s.agentType === 'agent';
|
|
187
|
+
const displayName = isAgent ? (s.agentName || 'Agent') : (s.llmName || 'LLM');
|
|
188
|
+
const icon = isAgent ? 'fa-robot' : 'fa-microchip';
|
|
189
|
+
|
|
190
|
+
const activeClasses = isActive
|
|
191
|
+
? 'bg-dark-hover/80 border-l-2 border-l-blue-500'
|
|
192
|
+
: 'hover:bg-dark-hover/40 border-l-2 border-l-transparent';
|
|
193
|
+
|
|
194
|
+
return `
|
|
195
|
+
<div data-session-id="${s.id}" class="session-item group flex items-start gap-2 px-3 py-2.5 cursor-pointer rounded-lg mb-0.5 transition-colors ${activeClasses}">
|
|
196
|
+
<div class="flex-1 min-w-0">
|
|
197
|
+
<div class="text-sm ${isActive ? 'text-gray-100' : 'text-gray-300'} truncate">${this.escapeHtml(s.title)}</div>
|
|
198
|
+
<div class="flex items-center gap-1.5 mt-0.5 text-xs text-gray-500">
|
|
199
|
+
<i class="fas ${icon} text-[10px]"></i>
|
|
200
|
+
<span class="truncate">${this.escapeHtml(displayName)}</span>
|
|
201
|
+
</div>
|
|
202
|
+
</div>
|
|
203
|
+
<button data-delete-id="${s.id}" class="session-delete-btn flex-shrink-0 text-gray-600 hover:text-red-400 opacity-0 group-hover:opacity-100 transition-opacity p-1 mt-0.5" title="Delete">
|
|
204
|
+
<i class="fas fa-xmark text-xs"></i>
|
|
205
|
+
</button>
|
|
206
|
+
</div>
|
|
207
|
+
`;
|
|
208
|
+
}).join('');
|
|
209
|
+
|
|
210
|
+
// Event listeners
|
|
211
|
+
list.querySelectorAll('.session-item').forEach(item => {
|
|
212
|
+
item.addEventListener('click', (e) => {
|
|
213
|
+
if (e.target.closest('.session-delete-btn')) return;
|
|
214
|
+
this.switchToSession(item.dataset.sessionId);
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
list.querySelectorAll('.session-delete-btn').forEach(btn => {
|
|
219
|
+
btn.addEventListener('click', (e) => {
|
|
220
|
+
e.stopPropagation();
|
|
221
|
+
this.deleteSession(btn.dataset.deleteId);
|
|
222
|
+
});
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
switchToSession(sessionId) {
|
|
227
|
+
// Abort any running stream
|
|
228
|
+
if (this.currentAbortController) {
|
|
229
|
+
this.currentAbortController.abort();
|
|
230
|
+
this.currentAbortController = null;
|
|
231
|
+
}
|
|
232
|
+
this.isLoading = false;
|
|
233
|
+
|
|
234
|
+
const session = sessionStore.get(sessionId);
|
|
235
|
+
if (!session) return;
|
|
236
|
+
|
|
237
|
+
sessionStore.setActiveId(sessionId);
|
|
238
|
+
|
|
239
|
+
// Update store with this session's agent/LLM
|
|
47
240
|
const agents = store.get('agents') || [];
|
|
48
241
|
const llms = store.get('llms') || [];
|
|
49
|
-
const selectionType = store.get('selectionType');
|
|
50
|
-
const selectedAgent = store.get('selectedAgent');
|
|
51
|
-
const selectedLlm = store.get('selectedLlm');
|
|
52
242
|
|
|
53
|
-
if (
|
|
243
|
+
if (session.agentType === 'agent') {
|
|
244
|
+
const agent = agents.find(a => a.name === session.agentName);
|
|
245
|
+
store.set('selectedAgent', agent || null);
|
|
246
|
+
store.set('selectedLlm', null);
|
|
247
|
+
store.set('selectionType', 'agent');
|
|
248
|
+
} else {
|
|
249
|
+
const llm = llms.find(l => l.name === session.llmName);
|
|
250
|
+
store.set('selectedLlm', llm || null);
|
|
251
|
+
store.set('selectedAgent', null);
|
|
252
|
+
store.set('selectionType', 'llm');
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
this.restoreMessages(session);
|
|
256
|
+
this.updateChatHeader(session);
|
|
257
|
+
this.renderSessionList();
|
|
258
|
+
this.updateUiState();
|
|
259
|
+
|
|
260
|
+
// Close sidebar on mobile after selecting
|
|
261
|
+
if (this._isMobile()) {
|
|
262
|
+
this.toggleSidebar(false);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
const input = this.querySelector('#chatInput');
|
|
266
|
+
if (input) {
|
|
267
|
+
input.disabled = false;
|
|
268
|
+
input.readOnly = false;
|
|
269
|
+
input.classList.remove('cursor-pointer');
|
|
270
|
+
input.focus();
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
async restoreMessages(session) {
|
|
275
|
+
const container = this.querySelector('#chatMessages');
|
|
276
|
+
if (!container) return;
|
|
277
|
+
container.innerHTML = '';
|
|
54
278
|
|
|
55
|
-
if (
|
|
56
|
-
|
|
279
|
+
if (session.messages.length === 0) {
|
|
280
|
+
this._appendWelcomeMessage(container);
|
|
57
281
|
return;
|
|
58
282
|
}
|
|
59
283
|
|
|
60
|
-
|
|
284
|
+
for (const msg of session.messages) {
|
|
285
|
+
if (msg.role === 'user') {
|
|
286
|
+
this.appendMessage('user', msg.content);
|
|
287
|
+
} else {
|
|
288
|
+
this.appendRestoredAssistantMessage(msg.content);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// Check if server still has this session (survives restarts)
|
|
293
|
+
try {
|
|
294
|
+
const exists = await api.checkSession(session.id);
|
|
295
|
+
if (!exists) {
|
|
296
|
+
this._appendSessionResetBanner(container);
|
|
297
|
+
}
|
|
298
|
+
} catch {
|
|
299
|
+
// Server unreachable — skip banner
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
appendRestoredAssistantMessage(content) {
|
|
304
|
+
const container = this.querySelector('#chatMessages');
|
|
305
|
+
const div = document.createElement('div');
|
|
306
|
+
div.className = 'response-wrapper';
|
|
307
|
+
|
|
308
|
+
const bubble = document.createElement('div');
|
|
309
|
+
bubble.className = 'flex justify-start';
|
|
310
|
+
bubble.innerHTML = `
|
|
311
|
+
<div class="response-bubble-inner max-w-4xl bg-dark-surface border border-dark-border rounded-3xl px-5 py-3 text-gray-100 text-[15px] leading-relaxed relative group">
|
|
312
|
+
<div class="response-content markdown-content"></div>
|
|
313
|
+
</div>
|
|
314
|
+
`;
|
|
315
|
+
|
|
316
|
+
const contentDiv = bubble.querySelector('.response-content');
|
|
317
|
+
const rendered = markdownRenderer.render(content);
|
|
318
|
+
contentDiv.innerHTML = rendered;
|
|
319
|
+
markdownRenderer.highlightCode(contentDiv);
|
|
320
|
+
|
|
321
|
+
div.appendChild(bubble);
|
|
322
|
+
container.appendChild(div);
|
|
323
|
+
container.scrollTop = container.scrollHeight;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
showNewSessionModal() {
|
|
327
|
+
// Remove existing modal if any
|
|
328
|
+
const existing = document.querySelector('#newSessionModal');
|
|
329
|
+
if (existing) existing.remove();
|
|
330
|
+
|
|
331
|
+
const agents = store.get('agents') || [];
|
|
332
|
+
const llms = store.get('llms') || [];
|
|
333
|
+
|
|
334
|
+
const overlay = document.createElement('div');
|
|
335
|
+
overlay.id = 'newSessionModal';
|
|
336
|
+
overlay.className = 'modal-backdrop fixed inset-0 z-50 flex items-center justify-center bg-black/70';
|
|
337
|
+
|
|
338
|
+
let itemsHtml = '';
|
|
61
339
|
|
|
62
|
-
// Agents section
|
|
63
340
|
if (agents.length > 0) {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
<div
|
|
69
|
-
<div class="
|
|
70
|
-
|
|
71
|
-
<div class="font-medium text-gray-200 mb-0.5">${agent.name}</div>
|
|
72
|
-
<div class="text-xs text-gray-500 line-clamp-2">${agent.description}</div>
|
|
73
|
-
</div>
|
|
74
|
-
${isSelected ? '<i class="fas fa-check text-blue-400 ml-2 mt-1"></i>' : ''}
|
|
75
|
-
</div>
|
|
341
|
+
itemsHtml += '<div class="px-4 py-2 text-xs font-semibold text-gray-400 uppercase tracking-wider">Agents</div>';
|
|
342
|
+
itemsHtml += agents.map(a => `
|
|
343
|
+
<button data-type="agent" data-name="${this.escapeHtml(a.name)}" class="modal-pick-item w-full text-left px-4 py-3 hover:bg-dark-hover cursor-pointer transition-colors border-b border-dark-border/50 flex items-center gap-3">
|
|
344
|
+
<i class="fas fa-robot text-blue-400 text-sm"></i>
|
|
345
|
+
<div class="flex-1 min-w-0">
|
|
346
|
+
<div class="text-sm font-medium text-gray-200">${this.escapeHtml(a.name)}</div>
|
|
347
|
+
<div class="text-xs text-gray-500 truncate">${this.escapeHtml(a.description || '')}</div>
|
|
76
348
|
</div>
|
|
77
|
-
|
|
78
|
-
|
|
349
|
+
</button>
|
|
350
|
+
`).join('');
|
|
79
351
|
}
|
|
80
352
|
|
|
81
|
-
// LLMs section
|
|
82
353
|
if (llms.length > 0) {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
<div
|
|
88
|
-
<div class="
|
|
89
|
-
|
|
90
|
-
<div class="font-medium text-gray-200 mb-0.5">${llm.name}</div>
|
|
91
|
-
<div class="text-xs text-gray-500 line-clamp-2">${llm.model}</div>
|
|
92
|
-
</div>
|
|
93
|
-
${isSelected ? '<i class="fas fa-check text-blue-400 ml-2 mt-1"></i>' : ''}
|
|
94
|
-
</div>
|
|
354
|
+
itemsHtml += '<div class="px-4 py-2 text-xs font-semibold text-gray-400 uppercase tracking-wider">LLMs</div>';
|
|
355
|
+
itemsHtml += llms.map(l => `
|
|
356
|
+
<button data-type="llm" data-name="${this.escapeHtml(l.name)}" class="modal-pick-item w-full text-left px-4 py-3 hover:bg-dark-hover cursor-pointer transition-colors border-b border-dark-border/50 flex items-center gap-3">
|
|
357
|
+
<i class="fas fa-microchip text-purple-400 text-sm"></i>
|
|
358
|
+
<div class="flex-1 min-w-0">
|
|
359
|
+
<div class="text-sm font-medium text-gray-200">${this.escapeHtml(l.name)}</div>
|
|
360
|
+
<div class="text-xs text-gray-500 truncate">${this.escapeHtml(l.model || '')}</div>
|
|
95
361
|
</div>
|
|
96
|
-
|
|
97
|
-
|
|
362
|
+
</button>
|
|
363
|
+
`).join('');
|
|
98
364
|
}
|
|
99
365
|
|
|
100
|
-
|
|
366
|
+
if (!itemsHtml) {
|
|
367
|
+
itemsHtml = '<div class="text-gray-500 text-sm text-center py-8">No agents or LLMs available</div>';
|
|
368
|
+
}
|
|
101
369
|
|
|
102
|
-
|
|
370
|
+
overlay.innerHTML = `
|
|
371
|
+
<div class="modal-content bg-dark-surface border border-dark-border rounded-2xl shadow-2xl w-[420px] max-w-[90vw] max-h-[70vh] flex flex-col overflow-hidden">
|
|
372
|
+
<div class="flex items-center justify-between px-5 py-4 border-b border-dark-border">
|
|
373
|
+
<h3 class="text-lg font-semibold text-gray-100">New conversation</h3>
|
|
374
|
+
<button id="closeNewSessionModal" class="text-gray-400 hover:text-gray-200 transition-colors p-1">
|
|
375
|
+
<i class="fas fa-xmark"></i>
|
|
376
|
+
</button>
|
|
377
|
+
</div>
|
|
378
|
+
<div class="overflow-y-auto custom-scrollbar flex-1">
|
|
379
|
+
${itemsHtml}
|
|
380
|
+
</div>
|
|
381
|
+
</div>
|
|
382
|
+
`;
|
|
383
|
+
|
|
384
|
+
document.body.appendChild(overlay);
|
|
385
|
+
|
|
386
|
+
// Close on backdrop click
|
|
387
|
+
overlay.addEventListener('click', (e) => {
|
|
388
|
+
if (e.target === overlay) overlay.remove();
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
overlay.querySelector('#closeNewSessionModal').addEventListener('click', () => overlay.remove());
|
|
392
|
+
|
|
393
|
+
// Pick handler
|
|
394
|
+
overlay.querySelectorAll('.modal-pick-item').forEach(item => {
|
|
103
395
|
item.addEventListener('click', () => {
|
|
104
396
|
const type = item.dataset.type;
|
|
105
397
|
const name = item.dataset.name;
|
|
106
398
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
const isSwitching = !(type === currentType && name === currentName);
|
|
114
|
-
|
|
115
|
-
if (type === 'agent') {
|
|
116
|
-
const agent = agents.find(a => a.name === name);
|
|
117
|
-
store.set('selectedAgent', agent);
|
|
118
|
-
store.set('selectedLlm', null);
|
|
119
|
-
store.set('selectionType', 'agent');
|
|
120
|
-
} else if (type === 'llm') {
|
|
121
|
-
const llm = llms.find(l => l.name === name);
|
|
122
|
-
store.set('selectedLlm', llm);
|
|
123
|
-
store.set('selectedAgent', null);
|
|
124
|
-
store.set('selectionType', 'llm');
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// Clear chat history when switching
|
|
128
|
-
if (isSwitching) {
|
|
129
|
-
this.clearChatHistory();
|
|
130
|
-
}
|
|
399
|
+
const session = sessionStore.create({
|
|
400
|
+
agentName: type === 'agent' ? name : null,
|
|
401
|
+
agentType: type,
|
|
402
|
+
llmName: type === 'llm' ? name : null
|
|
403
|
+
});
|
|
131
404
|
|
|
132
|
-
|
|
133
|
-
this.
|
|
134
|
-
this.renderAgentDropdown(); // Re-render to update selection checkmark
|
|
405
|
+
overlay.remove();
|
|
406
|
+
this.switchToSession(session.id);
|
|
135
407
|
});
|
|
136
408
|
});
|
|
137
409
|
}
|
|
138
410
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
const
|
|
142
|
-
|
|
143
|
-
|
|
411
|
+
deleteSession(sessionId) {
|
|
412
|
+
sessionStore.delete(sessionId);
|
|
413
|
+
const activeId = sessionStore.getActiveId();
|
|
414
|
+
|
|
415
|
+
if (!activeId || activeId === sessionId) {
|
|
416
|
+
// Switch to most recent remaining session
|
|
417
|
+
const sessions = sessionStore.getAll();
|
|
418
|
+
if (sessions.length > 0) {
|
|
419
|
+
this.switchToSession(sessions[0].id);
|
|
420
|
+
} else {
|
|
421
|
+
this.showEmptyState();
|
|
422
|
+
this.renderSessionList();
|
|
423
|
+
}
|
|
424
|
+
} else {
|
|
425
|
+
this.renderSessionList();
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
showEmptyState() {
|
|
430
|
+
const container = this.querySelector('#chatMessages');
|
|
431
|
+
if (container) {
|
|
432
|
+
container.innerHTML = `
|
|
433
|
+
<div class="flex-1 flex items-center justify-center h-full">
|
|
434
|
+
<div class="text-center text-gray-500">
|
|
435
|
+
<i class="fas fa-comments text-4xl mb-4 text-gray-600"></i>
|
|
436
|
+
<p class="text-lg">Start a new conversation</p>
|
|
437
|
+
<p class="text-sm mt-1">Click "New chat" to begin</p>
|
|
438
|
+
</div>
|
|
439
|
+
</div>
|
|
440
|
+
`;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
this.updateChatHeader(null);
|
|
444
|
+
|
|
445
|
+
const input = this.querySelector('#chatInput');
|
|
446
|
+
if (input) {
|
|
447
|
+
input.disabled = false;
|
|
448
|
+
input.readOnly = true;
|
|
449
|
+
input.classList.add('cursor-pointer');
|
|
450
|
+
}
|
|
451
|
+
|
|
144
452
|
const btn = this.querySelector('#sendMessageBtn');
|
|
453
|
+
if (btn) btn.disabled = true;
|
|
454
|
+
}
|
|
145
455
|
|
|
146
|
-
|
|
456
|
+
updateChatHeader(session) {
|
|
457
|
+
const header = this.querySelector('#chatHeader');
|
|
458
|
+
if (!header) return;
|
|
147
459
|
|
|
148
|
-
if (
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
460
|
+
if (!session) {
|
|
461
|
+
header.innerHTML = '<span class="text-gray-500">No conversation selected</span>';
|
|
462
|
+
return;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
const isAgent = session.agentType === 'agent';
|
|
466
|
+
const name = isAgent ? (session.agentName || 'Agent') : (session.llmName || 'LLM');
|
|
467
|
+
const badgeText = isAgent ? 'Agent' : 'LLM';
|
|
468
|
+
const badgeColor = isAgent ? 'bg-blue-500/20 text-blue-400' : 'bg-purple-500/20 text-purple-400';
|
|
469
|
+
const icon = isAgent ? 'fa-robot' : 'fa-microchip';
|
|
470
|
+
|
|
471
|
+
let extraBadges = '';
|
|
472
|
+
if (isAgent) {
|
|
473
|
+
const agents = store.get('agents') || [];
|
|
474
|
+
const agent = agents.find(a => a.name === session.agentName);
|
|
475
|
+
if (agent) {
|
|
476
|
+
if (agent.publish?.enabled) {
|
|
477
|
+
const chatUrl = `/chat/${encodeURIComponent(agent.name)}`;
|
|
478
|
+
extraBadges += `<a href="${chatUrl}" target="_blank" class="text-xs px-2 py-0.5 rounded-full bg-green-500/20 text-green-400 hover:bg-green-500/30 transition-colors no-underline" title="Open published chat"><i class="fas fa-globe text-[10px]"></i> Published</a>`;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
const hasMemory = agent.memory === true || (agent.memory && agent.memory.enabled);
|
|
482
|
+
if (hasMemory) {
|
|
483
|
+
extraBadges += `<span class="text-xs px-2 py-0.5 rounded-full bg-amber-500/20 text-amber-400" title="Persistent memory enabled"><i class="fas fa-brain text-[10px]"></i> Memory</span>`;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
if (agent.tools?.length) {
|
|
487
|
+
const toolNames = agent.tools.map(t => typeof t === 'string' ? t : t.name);
|
|
488
|
+
const toolListHtml = toolNames.map(t => `<div class="tools-popover-item">${this.escapeHtml(t)}</div>`).join('');
|
|
489
|
+
extraBadges += `
|
|
490
|
+
<span class="tools-badge-wrapper">
|
|
491
|
+
<span class="text-xs px-2 py-0.5 rounded-full bg-gray-500/20 text-gray-400 cursor-default"><i class="fas fa-wrench text-[10px]"></i> ${toolNames.length} tool${toolNames.length !== 1 ? 's' : ''}</span>
|
|
492
|
+
<div class="tools-popover">${toolListHtml}</div>
|
|
493
|
+
</span>`;
|
|
494
|
+
}
|
|
495
|
+
}
|
|
152
496
|
}
|
|
153
497
|
|
|
154
|
-
|
|
498
|
+
header.innerHTML = `
|
|
499
|
+
<div class="flex items-center gap-2 flex-wrap">
|
|
500
|
+
<i class="fas ${icon} text-sm text-gray-400"></i>
|
|
501
|
+
<span class="font-medium text-gray-200">${this.escapeHtml(name)}</span>
|
|
502
|
+
<span class="text-xs px-2 py-0.5 rounded-full ${badgeColor}">${badgeText}</span>
|
|
503
|
+
${extraBadges}
|
|
504
|
+
</div>
|
|
505
|
+
`;
|
|
155
506
|
}
|
|
156
507
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
508
|
+
// --- File Attachments ---
|
|
509
|
+
|
|
510
|
+
handleFileSelect(e) {
|
|
511
|
+
const files = Array.from(e.target.files);
|
|
512
|
+
e.target.value = '';
|
|
513
|
+
|
|
514
|
+
const needsConversion = ['image/webp', 'image/bmp', 'image/tiff'];
|
|
515
|
+
|
|
516
|
+
for (const file of files) {
|
|
517
|
+
if (needsConversion.includes(file.type)) {
|
|
518
|
+
this.convertImageToJpeg(file);
|
|
164
519
|
} else {
|
|
165
|
-
|
|
520
|
+
const reader = new FileReader();
|
|
521
|
+
reader.onload = () => {
|
|
522
|
+
const dataUrl = reader.result;
|
|
523
|
+
const commaIdx = dataUrl.indexOf(',');
|
|
524
|
+
const base64 = dataUrl.slice(commaIdx + 1);
|
|
525
|
+
const mediaType = file.type || 'application/octet-stream';
|
|
526
|
+
|
|
527
|
+
this.pendingAttachments.push({ data: base64, mediaType, name: file.name });
|
|
528
|
+
this.renderAttachmentPreview();
|
|
529
|
+
};
|
|
530
|
+
reader.readAsDataURL(file);
|
|
166
531
|
}
|
|
167
532
|
}
|
|
168
533
|
}
|
|
169
534
|
|
|
535
|
+
convertImageToJpeg(file) {
|
|
536
|
+
const img = new Image();
|
|
537
|
+
const url = URL.createObjectURL(file);
|
|
538
|
+
img.onload = () => {
|
|
539
|
+
const canvas = document.createElement('canvas');
|
|
540
|
+
canvas.width = img.naturalWidth;
|
|
541
|
+
canvas.height = img.naturalHeight;
|
|
542
|
+
canvas.getContext('2d').drawImage(img, 0, 0);
|
|
543
|
+
URL.revokeObjectURL(url);
|
|
544
|
+
|
|
545
|
+
const dataUrl = canvas.toDataURL('image/jpeg', 0.92);
|
|
546
|
+
const base64 = dataUrl.split(',')[1];
|
|
547
|
+
this.pendingAttachments.push({ data: base64, mediaType: 'image/jpeg', name: file.name });
|
|
548
|
+
this.renderAttachmentPreview();
|
|
549
|
+
};
|
|
550
|
+
img.src = url;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
renderAttachmentPreview() {
|
|
554
|
+
const preview = this.querySelector('#attachmentPreview');
|
|
555
|
+
if (!preview) return;
|
|
556
|
+
|
|
557
|
+
if (this.pendingAttachments.length === 0) {
|
|
558
|
+
preview.classList.add('hidden');
|
|
559
|
+
preview.innerHTML = '';
|
|
560
|
+
return;
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
preview.classList.remove('hidden');
|
|
564
|
+
preview.innerHTML = this.pendingAttachments.map((att, i) => {
|
|
565
|
+
const isImage = att.mediaType.startsWith('image/');
|
|
566
|
+
const thumb = isImage
|
|
567
|
+
? `<img src="data:${att.mediaType};base64,${att.data}" class="w-10 h-10 object-cover rounded">`
|
|
568
|
+
: `<i class="fas fa-file text-gray-400 text-lg"></i>`;
|
|
569
|
+
return `
|
|
570
|
+
<div class="attachment-pill flex items-center gap-2 bg-dark-bg/60 border border-dark-border/50 rounded-lg px-2 py-1.5 text-xs text-gray-400">
|
|
571
|
+
${thumb}
|
|
572
|
+
<span class="max-w-[120px] truncate">${this.escapeHtml(att.name)}</span>
|
|
573
|
+
<button class="attachment-remove text-gray-500 hover:text-gray-300 ml-1" data-index="${i}">
|
|
574
|
+
<i class="fas fa-xmark text-xs"></i>
|
|
575
|
+
</button>
|
|
576
|
+
</div>
|
|
577
|
+
`;
|
|
578
|
+
}).join('');
|
|
579
|
+
|
|
580
|
+
preview.querySelectorAll('.attachment-remove').forEach(btn => {
|
|
581
|
+
btn.addEventListener('click', (e) => {
|
|
582
|
+
const idx = parseInt(e.currentTarget.dataset.index, 10);
|
|
583
|
+
this.pendingAttachments.splice(idx, 1);
|
|
584
|
+
this.renderAttachmentPreview();
|
|
585
|
+
});
|
|
586
|
+
});
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
clearAttachments() {
|
|
590
|
+
this.pendingAttachments = [];
|
|
591
|
+
this.renderAttachmentPreview();
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
// --- Messaging ---
|
|
595
|
+
|
|
170
596
|
async sendMessage() {
|
|
171
597
|
const input = this.querySelector('#chatInput');
|
|
172
598
|
const message = input.value.trim();
|
|
173
599
|
const selectionType = store.get('selectionType');
|
|
174
600
|
const agent = store.get('selectedAgent');
|
|
175
601
|
const llm = store.get('selectedLlm');
|
|
602
|
+
const activeId = sessionStore.getActiveId();
|
|
176
603
|
|
|
177
604
|
const selected = selectionType === 'agent' ? agent : llm;
|
|
605
|
+
const hasAttachments = this.pendingAttachments.length > 0;
|
|
606
|
+
|
|
607
|
+
if ((!message && !hasAttachments) || !selected || this.isLoading || !activeId) return;
|
|
178
608
|
|
|
179
|
-
|
|
609
|
+
// Capture attachments before clearing
|
|
610
|
+
const attachments = hasAttachments ? [...this.pendingAttachments] : null;
|
|
180
611
|
|
|
181
|
-
// Add user message
|
|
182
|
-
this.appendMessage('user', message);
|
|
612
|
+
// Add user message (with optional attachment thumbnails)
|
|
613
|
+
this.appendMessage('user', message || '(attached files)', { attachments });
|
|
614
|
+
sessionStore.addMessage(activeId, 'user', message || '(attached files)');
|
|
183
615
|
input.value = '';
|
|
184
616
|
input.style.height = 'auto';
|
|
617
|
+
this.clearAttachments();
|
|
185
618
|
|
|
186
619
|
this.isLoading = true;
|
|
187
620
|
this.updateUiState();
|
|
@@ -189,27 +622,52 @@ export class AgentsView extends Component {
|
|
|
189
622
|
const responseId = 'response-' + Date.now();
|
|
190
623
|
this.createResponseBubble(responseId);
|
|
191
624
|
|
|
625
|
+
this.currentAbortController = new AbortController();
|
|
626
|
+
this.streamUsageData = null;
|
|
627
|
+
this.startStreamTimer(responseId);
|
|
628
|
+
|
|
629
|
+
let finalContent = '';
|
|
630
|
+
let wasCancelled = false;
|
|
631
|
+
|
|
192
632
|
try {
|
|
193
633
|
if (selectionType === 'agent') {
|
|
194
|
-
await this.sendAgentMessage(agent, message, responseId);
|
|
634
|
+
finalContent = await this.sendAgentMessage(agent, message, responseId, attachments);
|
|
195
635
|
} else if (selectionType === 'llm') {
|
|
196
|
-
await this.sendLlmMessage(llm, message, responseId);
|
|
636
|
+
finalContent = await this.sendLlmMessage(llm, message, responseId, attachments);
|
|
197
637
|
}
|
|
198
638
|
} catch (e) {
|
|
199
|
-
|
|
639
|
+
if (e.name === 'AbortError') {
|
|
640
|
+
wasCancelled = true;
|
|
641
|
+
} else {
|
|
642
|
+
this.updateResponseError(responseId, `Error: ${e.message}`);
|
|
643
|
+
}
|
|
200
644
|
} finally {
|
|
645
|
+
this.stopStreamTimer(responseId, message, finalContent, wasCancelled);
|
|
646
|
+
this.currentAbortController = null;
|
|
201
647
|
this.isLoading = false;
|
|
202
648
|
this.updateUiState();
|
|
203
649
|
input.focus();
|
|
204
650
|
}
|
|
651
|
+
|
|
652
|
+
// Persist assistant response
|
|
653
|
+
if (finalContent) {
|
|
654
|
+
sessionStore.addMessage(activeId, 'assistant', finalContent);
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
// Re-render sidebar (title/ordering may have changed)
|
|
658
|
+
this.renderSessionList();
|
|
205
659
|
}
|
|
206
660
|
|
|
207
|
-
async sendAgentMessage(agent, message, responseId) {
|
|
661
|
+
async sendAgentMessage(agent, message, responseId, attachments) {
|
|
208
662
|
const inputVars = agent.inputVariables || ['message'];
|
|
209
663
|
const inputObj = {};
|
|
210
664
|
inputObj[inputVars[0] || 'message'] = message;
|
|
665
|
+
if (attachments) {
|
|
666
|
+
inputObj.attachments = attachments;
|
|
667
|
+
}
|
|
211
668
|
|
|
212
|
-
const
|
|
669
|
+
const activeId = sessionStore.getActiveId();
|
|
670
|
+
const res = await api.streamAgent(agent.name, inputObj, activeId, { signal: this.currentAbortController?.signal });
|
|
213
671
|
const reader = res.body.getReader();
|
|
214
672
|
const decoder = new TextDecoder();
|
|
215
673
|
|
|
@@ -224,6 +682,7 @@ export class AgentsView extends Component {
|
|
|
224
682
|
|
|
225
683
|
let currentContent = '';
|
|
226
684
|
let buffer = '';
|
|
685
|
+
let hasToolCalls = false;
|
|
227
686
|
|
|
228
687
|
while (true) {
|
|
229
688
|
const { done, value } = await reader.read();
|
|
@@ -233,7 +692,6 @@ export class AgentsView extends Component {
|
|
|
233
692
|
buffer += chunk;
|
|
234
693
|
|
|
235
694
|
const lines = buffer.split('\n');
|
|
236
|
-
// Keep the last partial line in the buffer
|
|
237
695
|
buffer = lines.pop() || '';
|
|
238
696
|
|
|
239
697
|
for (const line of lines) {
|
|
@@ -245,9 +703,19 @@ export class AgentsView extends Component {
|
|
|
245
703
|
|
|
246
704
|
try {
|
|
247
705
|
const event = JSON.parse(data);
|
|
706
|
+
|
|
707
|
+
// Handle server-side errors
|
|
708
|
+
if (event.error) {
|
|
709
|
+
this.updateResponseError(responseId, `Error: ${event.error}`);
|
|
710
|
+
return currentContent;
|
|
711
|
+
}
|
|
712
|
+
|
|
248
713
|
if (event.type === 'content') {
|
|
249
714
|
currentContent += event.content;
|
|
250
715
|
}
|
|
716
|
+
if (event.type === 'tool_start' || event.type === 'tool_end') {
|
|
717
|
+
hasToolCalls = true;
|
|
718
|
+
}
|
|
251
719
|
this.handleStreamEvent(event, responseId, currentContent, thinkingState);
|
|
252
720
|
} catch (e) {
|
|
253
721
|
console.error('Error parsing stream event', e, data);
|
|
@@ -255,10 +723,29 @@ export class AgentsView extends Component {
|
|
|
255
723
|
}
|
|
256
724
|
}
|
|
257
725
|
}
|
|
726
|
+
|
|
727
|
+
// Finalize any remaining thinking pill
|
|
728
|
+
const toolsDiv = bubble.querySelector('.tool-invocations');
|
|
729
|
+
this.finalizeThinkingPill(toolsDiv, thinkingState);
|
|
730
|
+
|
|
731
|
+
// If tools were called but no text content was produced, clear loading state
|
|
732
|
+
if (hasToolCalls && !currentContent.trim()) {
|
|
733
|
+
const loadingDots = contentDiv.querySelector('.loading-dots');
|
|
734
|
+
if (loadingDots) {
|
|
735
|
+
loadingDots.remove();
|
|
736
|
+
bubble.querySelector('.response-bubble-inner').classList.remove('py-4');
|
|
737
|
+
bubble.querySelector('.response-bubble-inner').classList.add('py-3');
|
|
738
|
+
contentDiv.classList.remove('flex', 'items-center', 'whitespace-pre-wrap');
|
|
739
|
+
contentDiv.innerHTML = '';
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
return currentContent;
|
|
258
744
|
}
|
|
259
745
|
|
|
260
|
-
async sendLlmMessage(llm, message, responseId) {
|
|
261
|
-
const
|
|
746
|
+
async sendLlmMessage(llm, message, responseId, attachments) {
|
|
747
|
+
const activeId = sessionStore.getActiveId();
|
|
748
|
+
const res = await api.streamLLM(llm.name, message, activeId, attachments, { signal: this.currentAbortController?.signal });
|
|
262
749
|
const reader = res.body.getReader();
|
|
263
750
|
const decoder = new TextDecoder();
|
|
264
751
|
|
|
@@ -269,8 +756,8 @@ export class AgentsView extends Component {
|
|
|
269
756
|
|
|
270
757
|
if (loadingDots) {
|
|
271
758
|
loadingDots.remove();
|
|
272
|
-
bubble.querySelector('.
|
|
273
|
-
bubble.querySelector('.
|
|
759
|
+
bubble.querySelector('.response-bubble-inner').classList.remove('py-4');
|
|
760
|
+
bubble.querySelector('.response-bubble-inner').classList.add('py-3');
|
|
274
761
|
contentDiv.classList.remove('flex', 'items-center', 'whitespace-pre-wrap');
|
|
275
762
|
contentDiv.innerHTML = '';
|
|
276
763
|
}
|
|
@@ -305,7 +792,17 @@ export class AgentsView extends Component {
|
|
|
305
792
|
const parsed = JSON.parse(data);
|
|
306
793
|
|
|
307
794
|
if (parsed.error) {
|
|
308
|
-
|
|
795
|
+
this.updateResponseError(responseId, `Error: ${parsed.error}`);
|
|
796
|
+
return fullContent;
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
if (parsed.type === 'usage') {
|
|
800
|
+
this.streamUsageData = {
|
|
801
|
+
input_tokens: parsed.input_tokens || 0,
|
|
802
|
+
output_tokens: parsed.output_tokens || 0,
|
|
803
|
+
total_tokens: parsed.total_tokens || 0,
|
|
804
|
+
};
|
|
805
|
+
continue;
|
|
309
806
|
}
|
|
310
807
|
|
|
311
808
|
const text = parsed.content || '';
|
|
@@ -321,176 +818,152 @@ export class AgentsView extends Component {
|
|
|
321
818
|
}
|
|
322
819
|
}
|
|
323
820
|
}
|
|
821
|
+
|
|
822
|
+
return fullContent;
|
|
324
823
|
}
|
|
325
824
|
|
|
326
825
|
renderLlmContentStreaming(contentDiv, fullContent, responseId, state) {
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
const
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
}
|
|
341
|
-
break;
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
// Add text before [THINK]
|
|
345
|
-
if (thinkStart > pos) {
|
|
346
|
-
const text = fullContent.slice(pos, thinkStart).trim();
|
|
347
|
-
if (text) {
|
|
348
|
-
parts.push({ type: 'text', content: text });
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
// Find the end of this think section
|
|
353
|
-
const thinkContentStart = thinkStart + 7; // After [THINK]
|
|
354
|
-
const thinkEnd = fullContent.indexOf('[/THINK]', thinkContentStart);
|
|
826
|
+
const existing = contentDiv.querySelector('.content-text');
|
|
827
|
+
if (existing) {
|
|
828
|
+
const renderedHtml = markdownRenderer.render(fullContent);
|
|
829
|
+
existing.innerHTML = renderedHtml;
|
|
830
|
+
markdownRenderer.highlightCode(existing);
|
|
831
|
+
} else {
|
|
832
|
+
const div = document.createElement('div');
|
|
833
|
+
div.className = 'content-text markdown-content';
|
|
834
|
+
div.innerHTML = markdownRenderer.render(fullContent);
|
|
835
|
+
markdownRenderer.highlightCode(div);
|
|
836
|
+
contentDiv.appendChild(div);
|
|
837
|
+
}
|
|
838
|
+
}
|
|
355
839
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
parts.push({ type: 'think', content: thinkContent, complete: false, index: thinkIndex });
|
|
360
|
-
thinkIndex++;
|
|
361
|
-
break;
|
|
362
|
-
} else {
|
|
363
|
-
// Complete think section
|
|
364
|
-
const thinkContent = fullContent.slice(thinkContentStart, thinkEnd).trim();
|
|
365
|
-
parts.push({ type: 'think', content: thinkContent, complete: true, index: thinkIndex });
|
|
366
|
-
thinkIndex++;
|
|
367
|
-
pos = thinkEnd + 8; // After [/THINK]
|
|
368
|
-
}
|
|
840
|
+
handleThinkingEvent(event, toolsDiv, thinkingState, container) {
|
|
841
|
+
if (!thinkingState.thinkingContent) {
|
|
842
|
+
thinkingState.thinkingContent = '';
|
|
369
843
|
}
|
|
844
|
+
thinkingState.thinkingContent += event.content;
|
|
845
|
+
|
|
846
|
+
// Create pill on first thinking chunk
|
|
847
|
+
if (!thinkingState.thinkingPill) {
|
|
848
|
+
const pill = document.createElement('div');
|
|
849
|
+
pill.className = 'thinking-pill tool-pill inline-flex items-center gap-1.5 bg-dark-bg/50 border border-dark-border/60 rounded-full px-2.5 py-1 text-xs text-purple-400 font-mono';
|
|
850
|
+
pill.innerHTML = `
|
|
851
|
+
<i class="fas fa-brain animate-pulse text-[10px]"></i>
|
|
852
|
+
<span>Thinking...</span>
|
|
853
|
+
`;
|
|
854
|
+
toolsDiv.appendChild(pill);
|
|
855
|
+
thinkingState.thinkingPill = pill;
|
|
856
|
+
container.scrollTop = container.scrollHeight;
|
|
857
|
+
}
|
|
858
|
+
}
|
|
370
859
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
for (let i = 0; i < parts.length; i++) {
|
|
375
|
-
const part = parts[i];
|
|
376
|
-
const existingChild = contentDiv.children[currentChildIndex];
|
|
377
|
-
|
|
378
|
-
if (part.type === 'text') {
|
|
379
|
-
if (existingChild && existingChild.classList.contains('content-text')) {
|
|
380
|
-
// Update existing text element with markdown
|
|
381
|
-
const renderedHtml = markdownRenderer.render(part.content);
|
|
382
|
-
existingChild.innerHTML = renderedHtml;
|
|
383
|
-
markdownRenderer.highlightCode(existingChild);
|
|
384
|
-
} else {
|
|
385
|
-
// Create new text element
|
|
386
|
-
const div = document.createElement('div');
|
|
387
|
-
div.className = 'content-text markdown-content';
|
|
388
|
-
const renderedHtml = markdownRenderer.render(part.content);
|
|
389
|
-
div.innerHTML = renderedHtml;
|
|
390
|
-
markdownRenderer.highlightCode(div);
|
|
391
|
-
if (existingChild) {
|
|
392
|
-
contentDiv.insertBefore(div, existingChild);
|
|
393
|
-
} else {
|
|
394
|
-
contentDiv.appendChild(div);
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
currentChildIndex++;
|
|
398
|
-
} else if (part.type === 'think') {
|
|
399
|
-
const thinkId = `think-${responseId}-${part.index}`;
|
|
400
|
-
|
|
401
|
-
if (existingChild && existingChild.classList.contains('think-section')) {
|
|
402
|
-
// Update existing think section
|
|
403
|
-
const label = existingChild.querySelector('.think-label');
|
|
404
|
-
const content = existingChild.querySelector('.think-content');
|
|
405
|
-
if (label) {
|
|
406
|
-
label.textContent = part.complete ? 'Thinking' : 'Thinking...';
|
|
407
|
-
}
|
|
408
|
-
if (content) {
|
|
409
|
-
const renderedHtml = markdownRenderer.render(part.content);
|
|
410
|
-
content.innerHTML = renderedHtml;
|
|
411
|
-
content.classList.add('markdown-content');
|
|
412
|
-
markdownRenderer.highlightCode(content);
|
|
413
|
-
}
|
|
414
|
-
} else {
|
|
415
|
-
// Create new think section with event listener
|
|
416
|
-
const section = document.createElement('div');
|
|
417
|
-
section.className = 'think-section mb-3 border-l-2 border-blue-500/40 pl-3 py-1';
|
|
418
|
-
section.dataset.thinkIndex = part.index;
|
|
419
|
-
|
|
420
|
-
const toggle = document.createElement('button');
|
|
421
|
-
toggle.className = 'think-toggle flex items-center gap-1.5 text-xs text-blue-400 hover:text-blue-300 py-1 cursor-pointer';
|
|
422
|
-
toggle.dataset.thinkId = thinkId;
|
|
423
|
-
|
|
424
|
-
toggle.innerHTML = `
|
|
425
|
-
<i class="fas fa-brain text-xs"></i>
|
|
426
|
-
<span class="font-medium think-label">${part.complete ? 'Thinking' : 'Thinking...'}</span>
|
|
427
|
-
<i class="fas fa-chevron-right text-[10px] transition-transform think-chevron"></i>
|
|
428
|
-
`;
|
|
429
|
-
|
|
430
|
-
const thinkContent = document.createElement('div');
|
|
431
|
-
thinkContent.id = thinkId;
|
|
432
|
-
thinkContent.className = 'think-content hidden text-sm text-gray-400 markdown-content mt-1 leading-relaxed';
|
|
433
|
-
const renderedHtml = markdownRenderer.render(part.content);
|
|
434
|
-
thinkContent.innerHTML = renderedHtml;
|
|
435
|
-
markdownRenderer.highlightCode(thinkContent);
|
|
436
|
-
|
|
437
|
-
// Add click handler ONCE when creating
|
|
438
|
-
toggle.addEventListener('click', (e) => {
|
|
439
|
-
e.preventDefault();
|
|
440
|
-
e.stopPropagation();
|
|
441
|
-
const content = section.querySelector('.think-content');
|
|
442
|
-
const chevron = section.querySelector('.think-chevron');
|
|
443
|
-
|
|
444
|
-
if (content && chevron) {
|
|
445
|
-
if (content.classList.contains('hidden')) {
|
|
446
|
-
content.classList.remove('hidden');
|
|
447
|
-
chevron.classList.remove('fa-chevron-right');
|
|
448
|
-
chevron.classList.add('fa-chevron-down');
|
|
449
|
-
} else {
|
|
450
|
-
content.classList.add('hidden');
|
|
451
|
-
chevron.classList.remove('fa-chevron-down');
|
|
452
|
-
chevron.classList.add('fa-chevron-right');
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
});
|
|
860
|
+
finalizeThinkingPill(toolsDiv, thinkingState) {
|
|
861
|
+
const pill = thinkingState.thinkingPill;
|
|
862
|
+
if (!pill) return;
|
|
456
863
|
|
|
457
|
-
|
|
458
|
-
|
|
864
|
+
const content = thinkingState.thinkingContent || '';
|
|
865
|
+
thinkingState.thinkingPill = null;
|
|
866
|
+
thinkingState.thinkingContent = '';
|
|
459
867
|
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
} else {
|
|
463
|
-
contentDiv.appendChild(section);
|
|
464
|
-
}
|
|
465
|
-
}
|
|
466
|
-
currentChildIndex++;
|
|
467
|
-
}
|
|
468
|
-
}
|
|
868
|
+
pill.className = 'thinking-pill tool-pill relative inline-flex items-center gap-1.5 bg-dark-bg/30 border border-dark-border/50 rounded-full px-2.5 py-1 text-xs text-gray-500 font-mono cursor-pointer hover:bg-dark-bg/60 hover:border-dark-border transition-colors';
|
|
869
|
+
pill.innerHTML = '';
|
|
469
870
|
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
871
|
+
const pillContent = document.createElement('span');
|
|
872
|
+
pillContent.className = 'inline-flex items-center gap-1.5';
|
|
873
|
+
pillContent.innerHTML = `
|
|
874
|
+
<i class="fas fa-brain text-purple-400 text-[10px]"></i>
|
|
875
|
+
<span>Thinking</span>
|
|
876
|
+
`;
|
|
877
|
+
pill.appendChild(pillContent);
|
|
878
|
+
|
|
879
|
+
const popover = document.createElement('div');
|
|
880
|
+
popover.className = 'hidden fixed z-50 bg-dark-surface border border-dark-border rounded-lg shadow-xl w-[400px] max-w-[90vw] p-3';
|
|
881
|
+
|
|
882
|
+
const popoverContent = document.createElement('div');
|
|
883
|
+
popoverContent.className = 'text-xs text-gray-400 max-h-64 overflow-y-auto markdown-content custom-scrollbar';
|
|
884
|
+
popoverContent.innerHTML = markdownRenderer.render(content);
|
|
885
|
+
markdownRenderer.highlightCode(popoverContent);
|
|
886
|
+
popover.appendChild(popoverContent);
|
|
887
|
+
pill.appendChild(popover);
|
|
888
|
+
|
|
889
|
+
pill.addEventListener('mouseenter', () => {
|
|
890
|
+
popover.classList.remove('hidden');
|
|
891
|
+
const pillRect = pill.getBoundingClientRect();
|
|
892
|
+
popover.style.bottom = (window.innerHeight - pillRect.top + 4) + 'px';
|
|
893
|
+
popover.style.top = 'auto';
|
|
894
|
+
if (pillRect.left + 400 > window.innerWidth - 16) {
|
|
895
|
+
popover.style.left = Math.max(8, pillRect.right - 400) + 'px';
|
|
896
|
+
} else {
|
|
897
|
+
popover.style.left = pillRect.left + 'px';
|
|
898
|
+
}
|
|
899
|
+
popover.style.right = 'auto';
|
|
900
|
+
});
|
|
901
|
+
pill.addEventListener('mouseleave', () => popover.classList.add('hidden'));
|
|
474
902
|
}
|
|
475
903
|
|
|
476
904
|
createResponseBubble(id) {
|
|
477
905
|
const container = this.querySelector('#chatMessages');
|
|
906
|
+
const wrapper = document.createElement('div');
|
|
907
|
+
wrapper.className = 'response-wrapper';
|
|
908
|
+
|
|
478
909
|
const div = document.createElement('div');
|
|
479
910
|
div.id = id;
|
|
480
911
|
div.className = 'flex justify-start';
|
|
481
912
|
div.innerHTML = `
|
|
482
|
-
<div class="max-w-4xl bg-dark-surface border border-dark-border rounded-3xl px-5 py-4 text-gray-100 text-[15px] leading-relaxed relative group">
|
|
913
|
+
<div class="response-bubble-inner max-w-4xl bg-dark-surface border border-dark-border rounded-3xl px-5 py-4 text-gray-100 text-[15px] leading-relaxed relative group">
|
|
483
914
|
<div class="response-content whitespace-pre-wrap flex items-center">
|
|
484
915
|
<div class="loading-dots flex gap-1">
|
|
485
916
|
<div class="w-2 h-2 bg-blue-500 rounded-full animate-bounce"></div>
|
|
486
|
-
<div class="w-2 h-2 bg-blue-500 rounded-full animate-bounce
|
|
487
|
-
<div class="w-2 h-2 bg-blue-500 rounded-full animate-bounce
|
|
917
|
+
<div class="w-2 h-2 bg-blue-500 rounded-full animate-bounce animation-delay-200"></div>
|
|
918
|
+
<div class="w-2 h-2 bg-blue-500 rounded-full animate-bounce animation-delay-400"></div>
|
|
488
919
|
</div>
|
|
489
920
|
</div>
|
|
490
|
-
<div class="tool-invocations
|
|
921
|
+
<div class="tool-invocations flex flex-wrap gap-1.5 mt-2"></div>
|
|
491
922
|
</div>
|
|
492
923
|
`;
|
|
493
|
-
|
|
924
|
+
|
|
925
|
+
wrapper.appendChild(div);
|
|
926
|
+
|
|
927
|
+
const statusBar = document.createElement('div');
|
|
928
|
+
statusBar.className = 'stream-status-bar flex items-center gap-2 mt-1.5 ml-1 text-xs text-gray-400';
|
|
929
|
+
statusBar.innerHTML = `
|
|
930
|
+
<div class="w-2 h-2 bg-blue-500 rounded-full animate-pulse-dot"></div>
|
|
931
|
+
<span class="stream-status-text">Generating...</span>
|
|
932
|
+
<span class="stream-elapsed text-gray-500">0.0s</span>
|
|
933
|
+
<button class="stream-cancel-btn ml-auto text-gray-500 hover:text-gray-300 text-xs px-2 py-0.5 rounded border border-dark-border hover:border-gray-500 transition-colors">
|
|
934
|
+
Stop
|
|
935
|
+
</button>
|
|
936
|
+
`;
|
|
937
|
+
wrapper.appendChild(statusBar);
|
|
938
|
+
|
|
939
|
+
statusBar.querySelector('.stream-cancel-btn').addEventListener('click', () => this.cancelCurrentStream());
|
|
940
|
+
|
|
941
|
+
const statsBar = document.createElement('div');
|
|
942
|
+
statsBar.className = 'stream-stats-bar hidden flex items-center gap-3 mt-1.5 ml-1 text-xs text-gray-500';
|
|
943
|
+
statsBar.innerHTML = `
|
|
944
|
+
<span class="flex items-center gap-1">
|
|
945
|
+
<i class="far fa-clock"></i>
|
|
946
|
+
<span class="stats-elapsed"></span>
|
|
947
|
+
</span>
|
|
948
|
+
<span class="text-dark-border">|</span>
|
|
949
|
+
<span class="flex items-center gap-1">
|
|
950
|
+
<i class="fas fa-arrow-up text-[9px]"></i>
|
|
951
|
+
<span class="stats-input-tokens"></span>
|
|
952
|
+
</span>
|
|
953
|
+
<span class="text-dark-border">|</span>
|
|
954
|
+
<span class="flex items-center gap-1">
|
|
955
|
+
<i class="fas fa-arrow-down text-[9px]"></i>
|
|
956
|
+
<span class="stats-output-tokens"></span>
|
|
957
|
+
</span>
|
|
958
|
+
<span class="text-dark-border">|</span>
|
|
959
|
+
<span class="flex items-center gap-1">
|
|
960
|
+
<i class="fas fa-bolt text-[9px]"></i>
|
|
961
|
+
<span class="stats-tps"></span>
|
|
962
|
+
</span>
|
|
963
|
+
`;
|
|
964
|
+
wrapper.appendChild(statsBar);
|
|
965
|
+
|
|
966
|
+
container.appendChild(wrapper);
|
|
494
967
|
container.scrollTop = container.scrollHeight;
|
|
495
968
|
}
|
|
496
969
|
|
|
@@ -503,65 +976,124 @@ export class AgentsView extends Component {
|
|
|
503
976
|
const loadingDots = contentDiv.querySelector('.loading-dots');
|
|
504
977
|
const container = this.querySelector('#chatMessages');
|
|
505
978
|
|
|
506
|
-
if (event.type === '
|
|
979
|
+
if (event.type === 'thinking') {
|
|
980
|
+
this.handleThinkingEvent(event, toolsDiv, thinkingState, container);
|
|
981
|
+
} else if (event.type === 'content') {
|
|
982
|
+
// Finalize any in-progress thinking pill
|
|
983
|
+
this.finalizeThinkingPill(toolsDiv, thinkingState);
|
|
507
984
|
if (loadingDots) {
|
|
508
985
|
loadingDots.remove();
|
|
509
|
-
|
|
510
|
-
bubble.querySelector('.
|
|
511
|
-
bubble.querySelector('.max-w-4xl').classList.add('py-3');
|
|
986
|
+
bubble.querySelector('.response-bubble-inner').classList.remove('py-4');
|
|
987
|
+
bubble.querySelector('.response-bubble-inner').classList.add('py-3');
|
|
512
988
|
contentDiv.classList.remove('flex', 'items-center', 'whitespace-pre-wrap');
|
|
513
|
-
// Clear any whitespace
|
|
514
989
|
contentDiv.innerHTML = '';
|
|
515
990
|
}
|
|
516
|
-
// Use the same rendering method as LLMs to handle [THINK] tags
|
|
517
991
|
this.renderLlmContentStreaming(contentDiv, currentContent, responseId, thinkingState);
|
|
518
|
-
// Scroll to bottom as content streams in
|
|
519
992
|
container.scrollTop = container.scrollHeight;
|
|
520
993
|
} else if (event.type === 'tool_start') {
|
|
994
|
+
this.finalizeThinkingPill(toolsDiv, thinkingState);
|
|
521
995
|
const toolId = `tool-${event.runId}`;
|
|
522
996
|
const toolEl = document.createElement('div');
|
|
523
997
|
toolEl.id = toolId;
|
|
524
|
-
toolEl.className = 'bg-dark-bg/50 border border-dark-border rounded-
|
|
998
|
+
toolEl.className = 'tool-pill inline-flex items-center gap-1.5 bg-dark-bg/50 border border-dark-border/60 rounded-full px-2.5 py-1 text-xs text-gray-400 font-mono';
|
|
999
|
+
toolEl.dataset.toolInput = typeof event.input === 'string' ? event.input : JSON.stringify(event.input, null, 2);
|
|
525
1000
|
toolEl.innerHTML = `
|
|
526
|
-
<i class="fas fa-
|
|
527
|
-
<span
|
|
1001
|
+
<i class="fas fa-circle-notch animate-spin text-blue-400 text-[10px]"></i>
|
|
1002
|
+
<span>${this.escapeHtml(event.tool)}</span>
|
|
528
1003
|
`;
|
|
529
1004
|
toolsDiv.appendChild(toolEl);
|
|
530
|
-
// Scroll to bottom when tool starts
|
|
531
1005
|
container.scrollTop = container.scrollHeight;
|
|
532
1006
|
|
|
533
|
-
// If we have loading dots, keep them until text arrives
|
|
534
1007
|
} else if (event.type === 'tool_end') {
|
|
535
1008
|
const toolId = `tool-${event.runId}`;
|
|
536
1009
|
const toolEl = toolsDiv.querySelector(`#${toolId}`);
|
|
537
1010
|
if (toolEl) {
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
1011
|
+
const toolInput = toolEl.dataset.toolInput || '';
|
|
1012
|
+
const toolOutput = typeof event.output === 'string' ? event.output : JSON.stringify(event.output, null, 2);
|
|
1013
|
+
|
|
1014
|
+
toolEl.className = 'tool-pill relative inline-flex items-center gap-1.5 bg-dark-bg/30 border border-dark-border/50 rounded-full px-2.5 py-1 text-xs text-gray-500 font-mono cursor-pointer hover:bg-dark-bg/60 hover:border-dark-border transition-colors';
|
|
1015
|
+
toolEl.innerHTML = '';
|
|
1016
|
+
|
|
1017
|
+
const pillContent = document.createElement('span');
|
|
1018
|
+
pillContent.className = 'inline-flex items-center gap-1.5';
|
|
1019
|
+
pillContent.innerHTML = `
|
|
1020
|
+
<i class="fas fa-check text-green-500 text-[10px]"></i>
|
|
1021
|
+
<span>${this.escapeHtml(event.tool)}</span>
|
|
545
1022
|
`;
|
|
1023
|
+
toolEl.appendChild(pillContent);
|
|
1024
|
+
|
|
1025
|
+
const details = document.createElement('div');
|
|
1026
|
+
details.className = 'tool-invocation-details hidden absolute bottom-full mb-1 z-50 bg-dark-surface border border-dark-border rounded-lg shadow-xl w-[400px] max-w-[90vw]';
|
|
1027
|
+
|
|
1028
|
+
if (toolInput) {
|
|
1029
|
+
const inputSection = document.createElement('div');
|
|
1030
|
+
inputSection.className = 'p-3 border-b border-dark-border/50';
|
|
1031
|
+
inputSection.innerHTML = `<div class="text-xs font-semibold text-gray-400 mb-1">Input</div>`;
|
|
1032
|
+
const inputPre = document.createElement('pre');
|
|
1033
|
+
inputPre.className = 'text-xs text-gray-400 bg-dark-bg/60 rounded-md p-2 overflow-x-auto max-h-48 overflow-y-auto whitespace-pre-wrap break-all custom-scrollbar';
|
|
1034
|
+
inputPre.textContent = toolInput;
|
|
1035
|
+
inputSection.appendChild(inputPre);
|
|
1036
|
+
details.appendChild(inputSection);
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
const outputSection = document.createElement('div');
|
|
1040
|
+
outputSection.className = 'p-3';
|
|
1041
|
+
outputSection.innerHTML = `<div class="text-xs font-semibold text-gray-400 mb-1">Output</div>`;
|
|
1042
|
+
const outputPre = document.createElement('pre');
|
|
1043
|
+
outputPre.className = 'text-xs text-gray-400 bg-dark-bg/60 rounded-md p-2 overflow-x-auto max-h-48 overflow-y-auto whitespace-pre-wrap break-all custom-scrollbar';
|
|
1044
|
+
outputPre.textContent = toolOutput;
|
|
1045
|
+
outputSection.appendChild(outputPre);
|
|
1046
|
+
details.appendChild(outputSection);
|
|
1047
|
+
|
|
1048
|
+
toolEl.appendChild(details);
|
|
1049
|
+
|
|
1050
|
+
toolEl.addEventListener('click', (e) => {
|
|
1051
|
+
if (details.contains(e.target)) return;
|
|
1052
|
+
e.preventDefault();
|
|
1053
|
+
e.stopPropagation();
|
|
1054
|
+
toolsDiv.querySelectorAll('.tool-invocation-details:not(.hidden)').forEach(d => {
|
|
1055
|
+
if (d !== details) d.classList.add('hidden');
|
|
1056
|
+
});
|
|
1057
|
+
const wasHidden = details.classList.contains('hidden');
|
|
1058
|
+
details.classList.toggle('hidden');
|
|
1059
|
+
if (wasHidden) {
|
|
1060
|
+
const pillRect = toolEl.getBoundingClientRect();
|
|
1061
|
+
const containerRect = container.getBoundingClientRect();
|
|
1062
|
+
const spaceRight = containerRect.right - pillRect.left;
|
|
1063
|
+
if (spaceRight < 420) {
|
|
1064
|
+
details.style.right = '0';
|
|
1065
|
+
details.style.left = 'auto';
|
|
1066
|
+
} else {
|
|
1067
|
+
details.style.left = '0';
|
|
1068
|
+
details.style.right = 'auto';
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
});
|
|
546
1072
|
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
1073
|
+
const closeHandler = (e) => {
|
|
1074
|
+
if (!toolEl.contains(e.target)) {
|
|
1075
|
+
details.classList.add('hidden');
|
|
1076
|
+
}
|
|
1077
|
+
};
|
|
1078
|
+
document.addEventListener('click', closeHandler, { capture: true });
|
|
553
1079
|
container.scrollTop = container.scrollHeight;
|
|
1080
|
+
|
|
1081
|
+
if (event.tool === 'workspace_write' || event.tool === 'workspace_delete') {
|
|
1082
|
+
try {
|
|
1083
|
+
const result = JSON.parse(typeof event.output === 'string' ? event.output : JSON.stringify(event.output));
|
|
1084
|
+
if (result.success && (result.reloaded === 'agent' || result.unloaded === 'agent')) this.loadAgents();
|
|
1085
|
+
} catch { /* ignore parse errors */ }
|
|
1086
|
+
}
|
|
554
1087
|
}
|
|
555
1088
|
} else if (event.type === 'result') {
|
|
556
1089
|
if (loadingDots) {
|
|
557
1090
|
loadingDots.remove();
|
|
558
|
-
bubble.querySelector('.
|
|
559
|
-
bubble.querySelector('.
|
|
1091
|
+
bubble.querySelector('.response-bubble-inner').classList.remove('py-4');
|
|
1092
|
+
bubble.querySelector('.response-bubble-inner').classList.add('py-3');
|
|
560
1093
|
contentDiv.classList.remove('flex', 'items-center', 'whitespace-pre-wrap');
|
|
561
1094
|
contentDiv.innerHTML = '';
|
|
562
1095
|
}
|
|
563
1096
|
|
|
564
|
-
// Display structured output as formatted JSON
|
|
565
1097
|
const resultContainer = document.createElement('div');
|
|
566
1098
|
resultContainer.className = 'bg-dark-bg/50 border border-dark-border rounded-lg p-4';
|
|
567
1099
|
|
|
@@ -572,8 +1104,32 @@ export class AgentsView extends Component {
|
|
|
572
1104
|
resultContainer.appendChild(resultPre);
|
|
573
1105
|
contentDiv.appendChild(resultContainer);
|
|
574
1106
|
|
|
575
|
-
// Scroll to bottom
|
|
576
1107
|
container.scrollTop = container.scrollHeight;
|
|
1108
|
+
} else if (event.type === 'error') {
|
|
1109
|
+
if (loadingDots) {
|
|
1110
|
+
loadingDots.remove();
|
|
1111
|
+
bubble.querySelector('.response-bubble-inner').classList.remove('py-4');
|
|
1112
|
+
bubble.querySelector('.response-bubble-inner').classList.add('py-3');
|
|
1113
|
+
contentDiv.classList.remove('flex', 'items-center', 'whitespace-pre-wrap');
|
|
1114
|
+
}
|
|
1115
|
+
const errorDiv = document.createElement('div');
|
|
1116
|
+
errorDiv.className = 'text-red-400 text-sm mt-2';
|
|
1117
|
+
errorDiv.textContent = `Error: ${event.error}`;
|
|
1118
|
+
contentDiv.appendChild(errorDiv);
|
|
1119
|
+
container.scrollTop = container.scrollHeight;
|
|
1120
|
+
} else if (event.type === 'usage') {
|
|
1121
|
+
this.streamUsageData = {
|
|
1122
|
+
input_tokens: event.input_tokens || 0,
|
|
1123
|
+
output_tokens: event.output_tokens || 0,
|
|
1124
|
+
total_tokens: event.total_tokens || 0,
|
|
1125
|
+
};
|
|
1126
|
+
} else if (event.type === 'react_iteration') {
|
|
1127
|
+
const wrapper = bubble.closest('.response-wrapper');
|
|
1128
|
+
const statusText = wrapper?.querySelector('.stream-status-text');
|
|
1129
|
+
if (statusText) {
|
|
1130
|
+
const contextKB = (event.contextChars / 1024).toFixed(1);
|
|
1131
|
+
statusText.textContent = `Iteration ${event.iteration} · ${contextKB} KB context`;
|
|
1132
|
+
}
|
|
577
1133
|
}
|
|
578
1134
|
}
|
|
579
1135
|
|
|
@@ -588,8 +1144,13 @@ export class AgentsView extends Component {
|
|
|
588
1144
|
updateUiState() {
|
|
589
1145
|
const btn = this.querySelector('#sendMessageBtn');
|
|
590
1146
|
const input = this.querySelector('#chatInput');
|
|
591
|
-
|
|
592
|
-
if (
|
|
1147
|
+
const hasActiveSession = !!sessionStore.getActiveId();
|
|
1148
|
+
if (btn) btn.disabled = this.isLoading || !hasActiveSession;
|
|
1149
|
+
if (input) {
|
|
1150
|
+
input.disabled = this.isLoading;
|
|
1151
|
+
input.readOnly = !hasActiveSession;
|
|
1152
|
+
input.classList.toggle('cursor-pointer', !hasActiveSession);
|
|
1153
|
+
}
|
|
593
1154
|
}
|
|
594
1155
|
|
|
595
1156
|
appendMessage(role, content, metadata = {}) {
|
|
@@ -603,8 +1164,24 @@ export class AgentsView extends Component {
|
|
|
603
1164
|
const bubbleColor = isUser ? 'bg-dark-surface' : (hasError ? 'bg-red-900/20 border-red-900/30' : 'bg-dark-surface');
|
|
604
1165
|
const textColor = hasError ? 'text-red-300' : 'text-gray-100';
|
|
605
1166
|
|
|
1167
|
+
// Build attachment thumbnails for user messages
|
|
1168
|
+
let attachmentHtml = '';
|
|
1169
|
+
if (isUser && metadata.attachments && metadata.attachments.length > 0) {
|
|
1170
|
+
const thumbs = metadata.attachments.map(att => {
|
|
1171
|
+
if (att.mediaType.startsWith('image/')) {
|
|
1172
|
+
return `<img src="data:${att.mediaType};base64,${att.data}" class="w-16 h-16 object-cover rounded-lg border border-dark-border/50">`;
|
|
1173
|
+
}
|
|
1174
|
+
return `<div class="flex items-center gap-1.5 bg-dark-bg/60 border border-dark-border/50 rounded-lg px-2 py-1.5 text-xs text-gray-400">
|
|
1175
|
+
<i class="fas fa-file"></i>
|
|
1176
|
+
<span class="max-w-[100px] truncate">${this.escapeHtml(att.name)}</span>
|
|
1177
|
+
</div>`;
|
|
1178
|
+
}).join('');
|
|
1179
|
+
attachmentHtml = `<div class="flex flex-wrap gap-2 mb-2">${thumbs}</div>`;
|
|
1180
|
+
}
|
|
1181
|
+
|
|
606
1182
|
div.innerHTML = `
|
|
607
1183
|
<div class="max-w-4xl ${bubbleColor} border ${isUser ? 'border-transparent' : 'border-dark-border'} rounded-3xl px-5 py-3 ${textColor} text-[15px] leading-relaxed relative group">
|
|
1184
|
+
${attachmentHtml}
|
|
608
1185
|
<div class="whitespace-pre-wrap">${this.escapeHtml(content)}</div>
|
|
609
1186
|
${!isUser && !hasError ? `
|
|
610
1187
|
<button class="copy-btn absolute -bottom-6 left-0 text-gray-500 hover:text-gray-300 opacity-0 group-hover:opacity-100 transition-opacity p-1" title="Copy">
|
|
@@ -637,8 +1214,8 @@ export class AgentsView extends Component {
|
|
|
637
1214
|
<div class="max-w-4xl bg-dark-surface border border-dark-border rounded-3xl px-5 py-4">
|
|
638
1215
|
<div class="flex gap-1">
|
|
639
1216
|
<div class="w-2 h-2 bg-blue-500 rounded-full animate-bounce"></div>
|
|
640
|
-
<div class="w-2 h-2 bg-blue-500 rounded-full animate-bounce
|
|
641
|
-
<div class="w-2 h-2 bg-blue-500 rounded-full animate-bounce
|
|
1217
|
+
<div class="w-2 h-2 bg-blue-500 rounded-full animate-bounce animation-delay-200"></div>
|
|
1218
|
+
<div class="w-2 h-2 bg-blue-500 rounded-full animate-bounce animation-delay-400"></div>
|
|
642
1219
|
</div>
|
|
643
1220
|
</div>
|
|
644
1221
|
`;
|
|
@@ -658,30 +1235,116 @@ export class AgentsView extends Component {
|
|
|
658
1235
|
return div.innerHTML;
|
|
659
1236
|
}
|
|
660
1237
|
|
|
661
|
-
|
|
662
|
-
const
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
1238
|
+
_getRandomWelcomeMessage() {
|
|
1239
|
+
const messages = [
|
|
1240
|
+
'Awaiting your command, master.',
|
|
1241
|
+
'The agents are restless. Give them purpose.',
|
|
1242
|
+
'Ready when you are. No pressure... okay, maybe a little.',
|
|
1243
|
+
'Spinning up neurons... just kidding, I was already ready.',
|
|
1244
|
+
'All systems nominal. Your move, human.',
|
|
1245
|
+
'The orchestrator awaits. What shall we build today?',
|
|
1246
|
+
'Standing by. The agents are stretching their digital legs.',
|
|
1247
|
+
'Another day, another chance to orchestrate greatness.',
|
|
1248
|
+
'Agents assembled. Awaiting mission briefing.',
|
|
1249
|
+
'The stage is set. You are the conductor.',
|
|
1250
|
+
];
|
|
1251
|
+
return messages[Math.floor(Math.random() * messages.length)];
|
|
1252
|
+
}
|
|
667
1253
|
|
|
668
|
-
|
|
1254
|
+
_appendWelcomeMessage(container) {
|
|
669
1255
|
const div = document.createElement('div');
|
|
670
|
-
div.className = '
|
|
1256
|
+
div.className = 'welcome-container';
|
|
671
1257
|
div.innerHTML = `
|
|
672
|
-
<
|
|
673
|
-
|
|
674
|
-
|
|
1258
|
+
<svg class="welcome-orca" viewBox="0 0 220 140" xmlns="http://www.w3.org/2000/svg">
|
|
1259
|
+
<!-- Main body -->
|
|
1260
|
+
<path class="orca-body" d="
|
|
1261
|
+
M 30,68
|
|
1262
|
+
C 28,58 38,42 58,38
|
|
1263
|
+
C 68,35 74,30 78,18
|
|
1264
|
+
C 80,12 84,12 85,18
|
|
1265
|
+
C 87,28 86,35 92,38
|
|
1266
|
+
C 112,34 148,40 172,54
|
|
1267
|
+
C 176,50 182,44 188,40
|
|
1268
|
+
C 192,38 194,42 190,46
|
|
1269
|
+
C 186,50 184,54 182,56
|
|
1270
|
+
C 186,60 188,66 184,68
|
|
1271
|
+
C 180,70 178,66 176,62
|
|
1272
|
+
C 168,72 142,78 112,76
|
|
1273
|
+
C 82,74 52,70 38,66
|
|
1274
|
+
C 34,64 30,68 30,68 Z
|
|
1275
|
+
"/>
|
|
1276
|
+
<!-- Dorsal fin accent line -->
|
|
1277
|
+
<path class="orca-detail" d="M 72,38 C 74,28 78,18 80,14"/>
|
|
1278
|
+
<!-- Belly line -->
|
|
1279
|
+
<path class="orca-detail" d="M 42,64 C 62,70 100,74 140,72 C 158,70 170,66 176,62"/>
|
|
1280
|
+
<!-- Saddle patch -->
|
|
1281
|
+
<path class="orca-patch" d="M 92,40 C 102,38 112,40 108,48 C 104,54 90,50 92,40 Z"/>
|
|
1282
|
+
<!-- Eye patch -->
|
|
1283
|
+
<path class="orca-patch" d="M 44,52 C 50,48 60,50 56,58 C 52,62 42,58 44,52 Z"/>
|
|
1284
|
+
<!-- Eye -->
|
|
1285
|
+
<circle class="orca-eye" cx="42" cy="54" r="2.5"/>
|
|
1286
|
+
<!-- Pectoral fin -->
|
|
1287
|
+
<path class="orca-body" d="M 65,66 C 70,74 64,82 58,76 C 54,72 60,66 65,66 Z"/>
|
|
1288
|
+
<!-- Tail detail -->
|
|
1289
|
+
<path class="orca-detail" d="M 172,54 C 176,52 180,48 184,44"/>
|
|
1290
|
+
<path class="orca-detail" d="M 176,62 C 180,64 184,66 186,64"/>
|
|
1291
|
+
</svg>
|
|
1292
|
+
<div class="welcome-text">${this._getRandomWelcomeMessage()}</div>
|
|
1293
|
+
${this._renderSampleQuestionChips()}
|
|
675
1294
|
`;
|
|
676
1295
|
container.appendChild(div);
|
|
677
1296
|
|
|
678
|
-
|
|
679
|
-
|
|
1297
|
+
div.querySelectorAll('.sample-question-chip').forEach(chip => {
|
|
1298
|
+
chip.addEventListener('click', () => {
|
|
1299
|
+
const input = this.querySelector('#chatInput');
|
|
1300
|
+
if (input) {
|
|
1301
|
+
input.value = chip.textContent;
|
|
1302
|
+
input.focus();
|
|
1303
|
+
}
|
|
1304
|
+
});
|
|
1305
|
+
});
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1308
|
+
_renderSampleQuestionChips() {
|
|
1309
|
+
const agent = store.get('selectedAgent');
|
|
1310
|
+
const questions = agent?.sampleQuestions;
|
|
1311
|
+
if (!questions || questions.length === 0) return '';
|
|
1312
|
+
|
|
1313
|
+
const chips = questions.map(q =>
|
|
1314
|
+
`<button class="sample-question-chip bg-dark-surface border border-dark-border/60 hover:border-gray-500 text-gray-300 text-sm px-4 py-2 rounded-2xl transition-colors text-left">${this.escapeHtml(q)}</button>`
|
|
1315
|
+
).join('');
|
|
1316
|
+
|
|
1317
|
+
return `
|
|
1318
|
+
<div class="flex flex-wrap justify-center gap-2 max-w-2xl mt-4">${chips}</div>
|
|
1319
|
+
`;
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1322
|
+
_appendSessionResetBanner(container) {
|
|
1323
|
+
const div = document.createElement('div');
|
|
1324
|
+
div.className = 'session-reset-banner';
|
|
1325
|
+
div.innerHTML = `
|
|
1326
|
+
<div class="session-reset-line"></div>
|
|
1327
|
+
<span class="session-reset-label">
|
|
1328
|
+
<i class="fas fa-rotate-right"></i>
|
|
1329
|
+
Server restarted — new session
|
|
1330
|
+
</span>
|
|
1331
|
+
<div class="session-reset-line"></div>
|
|
1332
|
+
`;
|
|
1333
|
+
container.appendChild(div);
|
|
1334
|
+
container.scrollTop = container.scrollHeight;
|
|
680
1335
|
}
|
|
681
1336
|
|
|
682
1337
|
postRender() {
|
|
683
1338
|
const input = this.querySelector('#chatInput');
|
|
684
1339
|
|
|
1340
|
+
// Open new conversation modal when clicking input with no active session
|
|
1341
|
+
input.addEventListener('mousedown', (e) => {
|
|
1342
|
+
if (!sessionStore.getActiveId()) {
|
|
1343
|
+
e.preventDefault();
|
|
1344
|
+
this.showNewSessionModal();
|
|
1345
|
+
}
|
|
1346
|
+
});
|
|
1347
|
+
|
|
685
1348
|
// Auto-resize
|
|
686
1349
|
input.addEventListener('input', () => {
|
|
687
1350
|
input.style.height = 'auto';
|
|
@@ -698,60 +1361,74 @@ export class AgentsView extends Component {
|
|
|
698
1361
|
|
|
699
1362
|
this.querySelector('#sendMessageBtn').addEventListener('click', () => this.sendMessage());
|
|
700
1363
|
|
|
701
|
-
//
|
|
702
|
-
|
|
703
|
-
|
|
1364
|
+
// Attach button + file input
|
|
1365
|
+
this.querySelector('#attachBtn').addEventListener('click', () => this.querySelector('#fileInput').click());
|
|
1366
|
+
this.querySelector('#fileInput').addEventListener('change', (e) => this.handleFileSelect(e));
|
|
704
1367
|
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
this.toggleDropdown();
|
|
708
|
-
});
|
|
1368
|
+
// New chat button
|
|
1369
|
+
this.querySelector('#newChatBtn').addEventListener('click', () => this.showNewSessionModal());
|
|
709
1370
|
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
}
|
|
714
|
-
});
|
|
1371
|
+
// Mobile sidebar toggle
|
|
1372
|
+
this.querySelector('#sidebarToggleBtn').addEventListener('click', () => this.toggleSidebar(true));
|
|
1373
|
+
this.querySelector('#sidebarBackdrop').addEventListener('click', () => this.toggleSidebar(false));
|
|
715
1374
|
}
|
|
716
1375
|
|
|
717
1376
|
template() {
|
|
718
1377
|
return `
|
|
719
|
-
<div class="flex
|
|
720
|
-
<!--
|
|
721
|
-
<div id="
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
1378
|
+
<div class="flex h-full relative border border-dark-border rounded-xl overflow-hidden bg-dark-surface/30">
|
|
1379
|
+
<!-- Mobile sidebar backdrop -->
|
|
1380
|
+
<div id="sidebarBackdrop" class="hidden fixed inset-0 bg-black/50 z-30 md:hidden"></div>
|
|
1381
|
+
|
|
1382
|
+
<!-- Sidebar -->
|
|
1383
|
+
<div id="sidebar" class="hidden md:flex w-64 flex-shrink-0 bg-dark-bg md:bg-dark-bg/60 border-r border-dark-border/60 flex-col
|
|
1384
|
+
fixed md:relative inset-y-0 left-0 z-40 md:z-auto">
|
|
1385
|
+
<div class="p-3">
|
|
1386
|
+
<button id="newChatBtn" class="w-full flex items-center justify-center gap-2 px-3 py-2.5 hover:bg-dark-hover rounded-lg text-sm font-medium text-gray-300 transition-colors">
|
|
1387
|
+
<i class="fas fa-plus text-xs text-blue-400"></i>
|
|
1388
|
+
<span>New chat</span>
|
|
1389
|
+
</button>
|
|
726
1390
|
</div>
|
|
1391
|
+
<div id="sessionList" class="flex-1 overflow-y-auto custom-scrollbar px-2 pb-2"></div>
|
|
727
1392
|
</div>
|
|
728
1393
|
|
|
729
|
-
<!--
|
|
730
|
-
<div class="
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
<div class="
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
<span id="selectedAgentName">Select Agent/LLM</span>
|
|
741
|
-
<i class="fas fa-chevron-down text-xs text-gray-400"></i>
|
|
742
|
-
</button>
|
|
1394
|
+
<!-- Chat Area -->
|
|
1395
|
+
<div class="flex-1 flex flex-col min-w-0">
|
|
1396
|
+
<!-- Chat Header -->
|
|
1397
|
+
<div class="flex-shrink-0 flex items-center gap-2 px-3 md:px-5 py-3 border-b border-dark-border/40 text-sm">
|
|
1398
|
+
<button id="sidebarToggleBtn" class="md:hidden text-gray-400 hover:text-gray-200 p-1 -ml-1">
|
|
1399
|
+
<i class="fas fa-bars"></i>
|
|
1400
|
+
</button>
|
|
1401
|
+
<div id="chatHeader" class="flex-1 min-w-0">
|
|
1402
|
+
<span class="text-gray-500">No conversation selected</span>
|
|
1403
|
+
</div>
|
|
1404
|
+
</div>
|
|
743
1405
|
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
1406
|
+
<!-- Chat Messages -->
|
|
1407
|
+
<div id="chatMessages" class="flex-1 overflow-y-auto space-y-4 p-4 pr-2 pb-6 custom-scrollbar"></div>
|
|
1408
|
+
|
|
1409
|
+
<!-- Input Area -->
|
|
1410
|
+
<div class="p-3 pt-0">
|
|
1411
|
+
<div id="attachmentPreview" class="hidden flex flex-wrap gap-2 px-2 pb-2"></div>
|
|
1412
|
+
<div class="relative bg-dark-surface border border-dark-border/60 rounded-2xl focus-within:border-gray-500 transition-colors">
|
|
1413
|
+
<input type="file" id="fileInput" multiple accept="image/*,.pdf" class="hidden">
|
|
1414
|
+
<textarea id="chatInput" rows="1" readonly
|
|
1415
|
+
class="w-full bg-transparent pl-11 pr-14 py-3 text-gray-100 placeholder-gray-500 resize-none focus:outline-none max-h-[200px] cursor-pointer"
|
|
1416
|
+
placeholder="Ask anything"></textarea>
|
|
1417
|
+
|
|
1418
|
+
<div class="absolute bottom-2 left-2 flex items-center">
|
|
1419
|
+
<button id="attachBtn" type="button"
|
|
1420
|
+
class="text-gray-500 hover:text-gray-300 p-1.5 rounded-lg hover:bg-dark-hover transition-colors"
|
|
1421
|
+
title="Attach files">
|
|
1422
|
+
<i class="fas fa-plus text-sm"></i>
|
|
1423
|
+
</button>
|
|
749
1424
|
</div>
|
|
750
1425
|
|
|
751
|
-
<
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
1426
|
+
<div class="absolute bottom-2 right-2 flex items-center gap-2">
|
|
1427
|
+
<button id="sendMessageBtn" disabled
|
|
1428
|
+
class="bg-gradient-to-r from-blue-600 to-blue-700 hover:from-blue-500 hover:to-blue-600 disabled:opacity-50 disabled:cursor-not-allowed text-white p-2 rounded-lg transition-all shadow-lg shadow-blue-900/20">
|
|
1429
|
+
<i class="fas fa-paper-plane text-sm"></i>
|
|
1430
|
+
</button>
|
|
1431
|
+
</div>
|
|
755
1432
|
</div>
|
|
756
1433
|
</div>
|
|
757
1434
|
</div>
|