Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
91c87db
docs: add GitHub issue templates for bugs and features (closes #1)
Sep 10, 2026
8c81d58
feat: add streamable HTTP MCP server
forthfate Sep 15, 2026
25621bc
feat: run Orbit assistant through LangGraph MCP tools
forthfate Sep 15, 2026
845ca87
Merge pull request #103 from forthfate/feat/mcp-server
forthfate Sep 15, 2026
ac21658
Fix chat assistant input typography
forthfate Sep 15, 2026
46e7d97
Add assistant activity and MCP configuration
forthfate Sep 15, 2026
9af87af
feat: add high-level runner recipes
forthfate Sep 15, 2026
51a32bf
feat: show asset build usage (#107)
forthfate Sep 16, 2026
e4c1c10
feat: add global system readiness alert (#106)
forthfate Sep 16, 2026
075f472
feat: add runtime context to assistant prompt (#105)
forthfate Sep 16, 2026
40b3c70
Refine issue management lifecycle (#108)
forthfate Sep 17, 2026
069d16a
Reset build-scoped improvement and issue views
forthfate Sep 17, 2026
86c168e
Remember selected builds in improvement views
forthfate Sep 17, 2026
a0c1a10
Remove proposal decision history
forthfate Sep 17, 2026
f3c58bb
Embed issue management in improvements
forthfate Sep 17, 2026
64a95ef
Load control room data by active page
forthfate Sep 17, 2026
8e44ad5
Standardize page section spacing
forthfate Sep 17, 2026
73df446
Merge pull request #109 from forthfate/refactor/improvements-console
insighta-cloud Sep 17, 2026
9acfc22
Add Orbit Assistant coding agent tool (#111)
forthfate Sep 17, 2026
a460e8e
Add Assistant UI bridge tools
forthfate Sep 17, 2026
ef8824d
Remove workflow logs tab
forthfate Sep 17, 2026
70cad68
Remove prompt changes tab
forthfate Sep 17, 2026
03b2531
Show issue worktrees in run details
forthfate Sep 17, 2026
8c45527
Add issue discussion thread
forthfate Sep 18, 2026
17f37f0
Suggest prior issue commenters
forthfate Sep 18, 2026
ed73572
Refactor template lifecycle packages
forthfate Sep 18, 2026
4b678f8
Add reusable persona assets
forthfate Sep 18, 2026
84db626
test: cover split lifecycle graph phases
forthfate Sep 18, 2026
15567d2
Merge pull request #112 from forthfate/feat/ui-cleanup
insighta-cloud Sep 18, 2026
b62dd5e
Merge branch 'main' into feat/assistant-ui-bridge
insighta-cloud Sep 18, 2026
907b7df
Merge pull request #113 from forthfate/feat/assistant-ui-bridge
insighta-cloud Sep 18, 2026
12623b1
Add assistant MCP configuration editor
forthfate Sep 17, 2026
3274d43
Merge pull request #114 from forthfate/feat/assistant-mcp-config
insighta-cloud Sep 18, 2026
2b0dafb
Merge branch 'main' into feat/issue-discussion
insighta-cloud Sep 18, 2026
7b078d5
Merge pull request #115 from forthfate/feat/issue-discussion
insighta-cloud Sep 18, 2026
d2ba869
Merge branch 'main' into refactor/template-lifecycle-packages
insighta-cloud Sep 18, 2026
5088e43
Merge pull request #116 from forthfate/refactor/template-lifecycle-pa…
insighta-cloud Sep 18, 2026
91368bf
Merge branch 'main' into feat/persona-assets
insighta-cloud Sep 18, 2026
1dd177e
Merge pull request #117 from forthfate/feat/persona-assets
insighta-cloud Sep 18, 2026
cef49cf
feat: group assets into catalog tabs
forthfate Sep 18, 2026
9b3c8b2
Merge pull request #119 from forthfate/feat/assets-tabs
insighta-cloud Sep 18, 2026
87389f3
feat: separate MCP connection settings
forthfate Sep 19, 2026
35bb433
style: align settings section layouts
forthfate Sep 19, 2026
e1d415e
fix: keep asset tabs visible while loading
forthfate Sep 19, 2026
347f54f
Merge pull request #120 from forthfate/feat/mcp-settings-section
insighta-cloud Sep 19, 2026
f3544c5
Merge branch 'main' into style/settings-ui-alignment
insighta-cloud Sep 19, 2026
88c6e73
Merge pull request #121 from forthfate/style/settings-ui-alignment
insighta-cloud Sep 19, 2026
7775638
Merge branch 'main' into feat/github-issue-templates
insighta-cloud Sep 19, 2026
3e83d98
Merge pull request #68 from ghzhost/feat/github-issue-templates
insighta-cloud Sep 19, 2026
588b033
feat: simplify persona definitions
forthfate Sep 21, 2026
7e2ed64
fix: preserve persona selections in build API
forthfate Sep 21, 2026
0acb381
fix: show build run counts as tasks
forthfate Sep 21, 2026
25d24da
feat: record supervisor persona journeys
forthfate Sep 21, 2026
829e4d5
feat: make agent self-improvement worktree-based
forthfate Sep 21, 2026
93cbfbf
refactor: declare runner phases explicitly
forthfate Sep 21, 2026
9a81808
Merge branch 'main' into feat/agent-self-improvement-worktree
insighta-cloud Sep 21, 2026
ed5e60c
Merge pull request #123 from forthfate/refactor/explicit-runner-phases
insighta-cloud Sep 21, 2026
e94a22e
refactor: inline runner template policies
forthfate Sep 21, 2026
9183b33
Merge pull request #122 from forthfate/feat/agent-self-improvement-wo…
insighta-cloud Sep 21, 2026
8176e44
fix: deduplicate active issues and protect live runs
forthfate Sep 21, 2026
e4b210d
Merge pull request #124 from forthfate/fix/known-issue-dedup
insighta-cloud Sep 22, 2026
5982968
feat: add SDK command action helpers
forthfate Sep 22, 2026
0c5256a
feat: add structured runner validation helpers
forthfate Sep 22, 2026
7c9f9b4
chore: ignore local agent instructions
forthfate Sep 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 65 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
name: Bug Report
description: Report a reproducible problem or unexpected error in OpenOrbit
title: "[Bug]: "
labels: ["bug"]
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to report an issue! Please provide as much detail as possible to help us investigate and resolve it quickly.
- type: textarea
id: description
attributes:
label: Problem Description
description: A clear and concise description of the bug.
placeholder: Describe what happened...
validations:
required: true
- type: textarea
id: steps
attributes:
label: Steps to Reproduce
description: Exact steps to reproduce the behavior.
placeholder: |
1. Start the application with '...'
2. Navigate to '...'
3. Click on '...'
4. Observe error
validations:
required: true
- type: textarea
id: expected
attributes:
label: Expected Behavior
description: A clear and concise description of what you expected to happen.
placeholder: What did you expect to happen?
validations:
required: true
- type: textarea
id: actual
attributes:
label: Actual Behavior
description: What actually occurred, including any error messages or unexpected states.
placeholder: What happened instead?
validations:
required: true
- type: textarea
id: environment
attributes:
label: Environment & Versions
description: Relevant environment information (OS, Node version, Python version, browser, OpenOrbit version).
placeholder: |
- OS: [e.g. Linux Ubuntu 22.04 / macOS 14 / Windows 11]
- Python version: [e.g. 3.13.0]
- Node.js version: [e.g. 24.0.0]
- OpenOrbit version: [e.g. v0.8.0 or commit hash]
validations:
required: true
- type: textarea
id: additional-context
attributes:
label: Additional Context
description: Add any other context, logs, terminal outputs, or screenshots about the problem here.
placeholder: Optional additional logs or screenshots...
validations:
required: false
41 changes: 41 additions & 0 deletions .github/ISSUE_TEMPLATE/feature_request.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: Feature Request
description: Propose a new idea, enhancement, or capability for OpenOrbit
title: "[Feature]: "
labels: ["enhancement"]
body:
- type: markdown
attributes:
value: |
Thank you for suggesting a feature! Please provide details about what problem this feature solves and how it should work.
- type: textarea
id: problem
attributes:
label: Problem Statement / Motivation
description: Is your feature request related to a problem or limitation? Please describe.
placeholder: A clear and concise description of what the problem or use case is...
validations:
required: true
- type: textarea
id: proposed-solution
attributes:
label: Proposed Solution & Expected Behavior
description: A clear and concise description of what you want to happen and how it should look or behave.
placeholder: Describe your proposed design, UI behavior, or API capability...
validations:
required: true
- type: textarea
id: alternatives
attributes:
label: Alternatives Considered
description: Any alternative solutions or workarounds you have considered.
placeholder: Optional description of other approaches evaluated...
validations:
required: false
- type: textarea
id: additional-context
attributes:
label: Additional Context
description: Add any other context, mockup screenshots, or implementation suggestions here.
placeholder: Optional mockups, architectural notes, or links...
validations:
required: false
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ test-results/
openorbit-state.zip
conversations/
.orbit/
AGENTS.md
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ OpenOrbit exposes a local, versioned API:
- Swagger UI: `http://localhost:3000/api/docs`
- OpenAPI document: `http://localhost:3000/api/openapi.json`
- API base: `http://localhost:3000/api/v1`
- MCP (Streamable HTTP): `http://localhost:3000/mcp/`

Read the [API reference](docs/API.md) for endpoint details. To add reusable automation, create a Python runner with explicit lifecycle phases:

Expand Down
159 changes: 159 additions & 0 deletions backend/app/assistant_graph.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
"""LangGraph orchestration for the local Orbit assistant."""

from __future__ import annotations

import asyncio
import json
from typing import Any, Callable, TypedDict

from coding_agents import execution_environment_context
from langgraph.graph import END, START, StateGraph
from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client

from .assistant_tools import DEFAULT_MCP_URL, AssistantToolExecutor
from .assistant_ui import AssistantUiToolExecutor
from .providers import AzureOpenAIProvider, BedrockProvider, ModelSettings


class AssistantState(TypedDict, total=False):
prompt: str
response: str


class LocalMcpTools:
"""Expose the mounted OpenOrbit MCP server as native model function tools."""

def __init__(self, url: str = DEFAULT_MCP_URL):
self.url = url

async def _list_tools(self) -> list[dict[str, Any]]:
async with streamablehttp_client(self.url) as (read, write, _):
async with ClientSession(read, write) as session:
await session.initialize()
result = await session.list_tools()
return [
{
"name": tool.name,
"description": tool.description or "OpenOrbit MCP tool.",
"parameters": tool.inputSchema,
}
for tool in result.tools
]

async def _call_tool(self, name: str, arguments: dict[str, Any]) -> str:
async with streamablehttp_client(self.url) as (read, write, _):
async with ClientSession(read, write) as session:
await session.initialize()
result = await session.call_tool(name, arguments)
if result.isError:
return json.dumps({"error": "MCP tool failed", "content": result.content}, default=str)
return json.dumps({"content": result.content}, default=str, ensure_ascii=False)

@staticmethod
def _run(coro: Any) -> Any:
return asyncio.run(coro)

def definitions(self) -> list[dict[str, Any]]:
try:
return self._run(self._list_tools())
except Exception:
# The assistant remains usable while the local server is starting.
return []

def execute(self, name: str, arguments: dict[str, Any]) -> str:
try:
return self._run(self._call_tool(name, arguments))
except Exception as error:
return json.dumps({"error": f"MCP unavailable: {error}"})


class OrbitAssistantGraph:
"""A small, explicit LangGraph for one bounded assistant turn.

The model node can use both the local bounded workspace tools and the
mounted MCP control-room tools. Provider adapters retain the native tool
call protocol, while LangGraph owns the turn state and final response.
"""

def __init__(
self,
provider: AzureOpenAIProvider | BedrockProvider,
settings: ModelSettings,
local_tools: AssistantToolExecutor,
mcp_tools: LocalMcpTools | None = None,
ui_tools: AssistantUiToolExecutor | None = None,
on_activity: Callable[[str, str | None], None] | None = None,
):
self.provider = provider
self.settings = settings
self.local_tools = local_tools
self.mcp_tools = mcp_tools or LocalMcpTools(local_tools.settings["mcp_server_url"])
self.ui_tools = ui_tools
self.on_activity = on_activity
graph = StateGraph(AssistantState)
graph.add_node("model", self._model)
graph.add_edge(START, "model")
graph.add_edge("model", END)
self.graph = graph.compile()

def _model(self, state: AssistantState) -> AssistantState:
self._activity("thinking")
local_definitions = self.local_tools.definitions()
mcp_definitions = self.mcp_tools.definitions()
ui_definitions = self.ui_tools.definitions() if self.ui_tools else []
definitions = [*mcp_definitions, *local_definitions, *ui_definitions]

def execute(name: str, arguments: dict[str, Any]) -> str:
self._activity("working", name)
if any(tool["name"] == name for tool in mcp_definitions):
result = self.mcp_tools.execute(name, arguments)
elif self.ui_tools and any(tool["name"] == name for tool in ui_definitions):
result = self.ui_tools.execute(name, arguments)
else:
result = self.local_tools.execute(name, arguments)
self._activity("thinking")
return result

response = (
self.provider.complete_with_tools(self.settings, state["prompt"], definitions, execute)
if definitions
else self.provider.complete(self.settings, state["prompt"])
)
return {"response": response}

def _activity(self, phase: str, tool: str | None = None) -> None:
if self.on_activity:
self.on_activity(phase, tool)

def invoke(self, prompt: str) -> str:
result = self.graph.invoke({"prompt": prompt})
return str(result["response"])


def build_assistant_prompt(
content: str, history: list[tuple[str, str]], locale: str | None, ui_enabled: bool = False
) -> str:
prompt = (
"You are Orbit, a concise assistant for the local OpenOrbit control room.\n"
"Use the OpenOrbit MCP tools as the source of truth for local control-room state. "
"Read state before suggesting or taking any state-changing action.\n"
+ execution_environment_context()
)
if ui_enabled:
prompt += (
"Browser UI tools are available for this turn. For any question about the current Orbit "
"screen, visible component, selected item, open panel, dialog, form value, or any request "
"to change the Orbit UI, first call ui_get_context. Use ui_interact only after reading the "
"current UI context. Do not use file tools to infer browser UI state. File tools remain for "
"workspace files and coding tasks only.\n"
)
if locale:
prompt += f"Respond in BCP 47 locale '{locale}'.\n"
if history:
prompt += (
"Conversation so far:\n"
+ "\n".join(f"{role.title()}: {message}" for role, message in history)
+ "\n\n"
)
return prompt + f"User: {content}\nAssistant:"
Loading
Loading