Skip to content

Commit 95a8193

Browse files
committed
dev: ghost prototype atom developing
1 parent fd76a26 commit 95a8193

35 files changed

Lines changed: 2350 additions & 172 deletions

examples/jetarm_demo/jetarm_agent.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
async def run_agent(address: str = ADDRESS, container: Container | None = None):
2121
container = container or get_container()
2222
# 创建 Shell
23-
shell = new_ctml_shell(container=container)
23+
shell = new_ctml_shell(parent_container=container)
2424

2525
jetarm_chan = ZMQChannelProxy(
2626
name="jetarm",

examples/miku/main.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ async def run_agent(container: Container, speech: Speech | None = None):
8686
loop = asyncio.get_running_loop()
8787

8888
# 创建 Shell
89-
shell = new_ctml_shell(container=container)
89+
shell = new_ctml_shell(parent_container=container)
9090

9191
async def speaking():
9292
try:

examples/moss_agent.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ def run_moss_agent(container: Container):
8282
)
8383

8484
speech = get_example_speech(container)
85-
shell = new_ctml_shell(container=container, speech=speech, experimental=False)
85+
shell = new_ctml_shell(parent_container=container, speech=speech, experimental=False)
8686
shell.main_channel.import_channels(
8787
zmq_hub.as_channel(),
8888
# 浏览器

pyproject.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[project]
22
name = "ghoshell-moss"
3-
version = "0.1.0-alpha"
4-
description = "LLM-oriented operating system shell, providing interpreter for llm to control everything"
3+
version = "0.1.0-beta"
4+
description = "LLM-oriented operating system with streaming interpreting shell, and Intelligent Ghost inside it"
55
authors = [{ name = "thirdgerb" }, { name = "17wang" }]
66
license = { text = "Apache License 2.0" }
77
readme = "README.md"
@@ -50,6 +50,7 @@ audio = ["pulsectl>=24.12.0", "pyaudio>=0.2.14", "scipy>=1.15.3"]
5050
host = [
5151
"circus>=0.19.0",
5252
"eclipse-zenoh>=1.8.0",
53+
"pydantic-ai>=1.90.0",
5354
"uv>=0.11.8",
5455
"uvloop>=0.22.1",
5556
]

src/ghoshell_moss/cli/main.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import sys
33
from typing import Optional
44
from ghoshell_moss.cli.utils import (
5-
print_error, print_info,
5+
print_error,
66
print_panel, echo
77
)
88
from ghoshell_moss.cli import codex_cli

src/ghoshell_moss/cli/manifests_cli.py

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,8 @@ def _display_channel_table(channels: dict, is_filtered: bool):
334334
@manifest_app.command(name="primitives")
335335
def list_primitives(
336336
search: str = typer.Argument("", help="Search pattern for command name."),
337-
json_out: bool = typer.Option(False, "--json", help="Output as raw JSON for AI.")
337+
json_out: bool = typer.Option(False, "--json", help="Output as raw JSON for AI."),
338+
json_schema: bool = typer.Option(False, "--json-schema", help="Output with json schema")
338339
):
339340
"""
340341
Explore MOSS Primitives (Commands).
@@ -351,23 +352,29 @@ def list_primitives(
351352
"description": cmd.meta().description,
352353
"params": cmd.meta().json_schema
353354
} for name, cmd in results.items()}
354-
console.json(data=data)
355+
console.print_json(data=data)
355356
return
356-
357-
_display_command_detail(list(results.values())[0])
357+
if len(primitives) == 0:
358+
console.print("no primitive found")
359+
return
360+
for key, cmd in results.items():
361+
_display_command_detail(cmd, json_schema)
358362

359363

360-
def _display_command_detail(cmd):
364+
def _display_command_detail(cmd, with_json_schema: bool):
361365
meta = cmd.meta()
362-
console.print(f"\n[bold green]Command:[/bold green] {meta.name}")
366+
console.print(f"\n[bold green]==== Command:[/bold green] {meta.name} ====")
363367
console.print(f"[dim]Dynamic: {cmd.is_dynamic()}[/dim]\n")
364368

365369
# 重点展示接口定义
366-
console.print(Panel(cmd.meta().interface, title="Interface Prompt", border_style="yellow"))
370+
console.print(f"[dim]Interface:[/dim]\n")
371+
console.print(Syntax(cmd.meta().interface, 'python'))
367372

368373
# 展示 JSON Schema
369-
console.print("\n[bold]Arguments Schema:[/bold]")
370-
console.json(data=meta.json_schema)
374+
if with_json_schema and meta.json_schema is not None:
375+
console.print("\n[bold]Arguments Schema:[/bold]")
376+
console.print_json(data=meta.json_schema)
377+
console.print("")
371378

372379

373380
@manifest_app.command(name="contracts")

src/ghoshell_moss/cli/workspace_cli.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -123,16 +123,16 @@ def init_workspace(
123123
# 1. 路径选择逻辑 (极简命令行模式)
124124
if path is None:
125125
rprint("\n[bold cyan]MOSS Workspace Setup[/bold cyan]")
126-
rprint(f" 1) Home directory: [dim]{home_path}[/dim]")
127-
rprint(f" 2) Current directory: [dim]{cwd_path}[/dim]")
126+
rprint(f" 1) Current directory: [dim]{cwd_path}[/dim]")
127+
rprint(f" 2) Home directory: [dim]{home_path}[/dim]")
128128
rprint(f" 3) Custom path")
129129

130130
choice = typer.prompt("\nSelect an option", default="1", type=str)
131131

132132
if choice == "1":
133-
target_path = home_path
134-
elif choice == "2":
135133
target_path = cwd_path
134+
elif choice == "2":
135+
target_path = home_path
136136
elif choice == "3":
137137
custom_path = typer.prompt("Enter custom path", type=Path)
138138
target_path = custom_path.resolve()

src/ghoshell_moss/core/blueprint/channel_builder.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
"MessageType",
2020
"Builder",
2121
"MutableChannel",
22-
"new_channel"
22+
"new_channel", "new_command",
2323
]
2424

2525
"""

src/ghoshell_moss/core/blueprint/conversation.py

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
__all__ = [
1414
'Conversation', 'ConversationStore',
1515
'Reaction', 'Moment', 'ConversationMeta',
16-
'ArticulateContext',
16+
'ModelContext',
1717
]
1818

1919

@@ -80,6 +80,20 @@ class Moment(BaseModel, WithAdditional):
8080
description="与本轮思考决策相关的提示讯息. 只在当前轮次生效",
8181
)
8282

83+
def to_json(self, *, exclude_perspectives: bool = True) -> str:
84+
"""
85+
标准的序列化方式, 也方便存储.
86+
"""
87+
exclude = None
88+
if exclude_perspectives:
89+
exclude = {'perspectives'}
90+
return self.model_dump_json(
91+
exclude=exclude,
92+
ensure_ascii=False,
93+
exclude_none=True,
94+
exclude_defaults=True,
95+
)
96+
8397
def new_reaction(self) -> Reaction:
8498
"""生成下轮的接收池"""
8599
return Reaction(
@@ -194,7 +208,7 @@ class ConversationMeta(BaseModel, WithAdditional):
194208
_Logos = str
195209

196210

197-
class ArticulateContext(BaseModel, WithAdditional):
211+
class ModelContext(BaseModel, WithAdditional):
198212
"""
199213
为给大模型使用设计的数据结构.
200214
这个数据结构考虑可以存储, 方便调试还原每一个 AI 思考的关键帧.
@@ -317,11 +331,13 @@ def get_effective_messages(self) -> Iterable[Message]:
317331
pass
318332

319333
@abstractmethod
320-
def save(self) -> asyncio.Future[ConversationMeta]:
334+
def save(self, compact: bool | None = None) -> asyncio.Future[ConversationMeta]:
321335
"""
322-
保存当前 conversation, 可以不阻塞当前流程. 返回更新后的 meta 信息. 可能实际上变更了 id.
336+
保存当前 conversation.
337+
可以不阻塞当前流程. 返回更新后的 meta 信息. 可能实际上变更了 id.
323338
更新逻辑实际上会排队. 此外, Conversation 之所以是一个抽象类, 就是考虑内部实际上实现了 conversation policy.
324-
更新完毕后, Conversation 抽象内容物可能会变化.
339+
更新完毕后, Conversation 抽象内容物可能会变化. 具体的 Policy 由 Conversation 实现决定.
340+
:param compact: 为 None 表示 auto compact. 为 True 表示必须 Compact.
325341
"""
326342
pass
327343

src/ghoshell_moss/core/blueprint/ghost.py

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
from ghoshell_container import IoCContainer, Contracts
22
from typing_extensions import Self
33
from abc import ABC, abstractmethod
4-
from ghoshell_moss.core.blueprint.mindflow import Logos, Mindflow, Nucleus
5-
from ghoshell_moss.core.blueprint.conversation import ArticulateContext
4+
from ghoshell_moss.core.blueprint.mindflow import Logos, Mindflow, Nucleus, NucleusMeta, Articulator
5+
from ghoshell_moss.core.blueprint.conversation import ConversationStore, Conversation
66
from ghoshell_moss.core.concepts.channel import Channel
77
from ghoshell_moss.message import Message
88

@@ -23,6 +23,10 @@ def name(self) -> str:
2323
"""
2424
pass
2525

26+
@abstractmethod
27+
def nuclei_metas(self) -> list[NucleusMeta]:
28+
pass
29+
2630
@classmethod
2731
def version(cls) -> str:
2832
"""
@@ -35,7 +39,10 @@ def prototype(cls) -> str:
3539
"""
3640
返回 Ghost 型号.
3741
"""
38-
return cls.__name__
42+
prototype_name = cls.__name__
43+
if prototype_name.endswith('Meta'):
44+
prototype_name = prototype_name[:-4]
45+
return prototype_name
3946

4047
@property
4148
def identifier(self) -> str:
@@ -76,6 +83,8 @@ class Ghost(ABC):
7683
Ghost 的运行时.
7784
它基于环境提供的依赖启动, 启动后要提供
7885
能够被 moss 架构所使用的关键 API.
86+
87+
系统启动的时候, Ghost 和 GhostMeta 都应该设置到全局 IoC 容器里.
7988
"""
8089

8190
@property
@@ -123,6 +132,20 @@ def nuclei(self) -> list[Nucleus]:
123132
"""
124133
return []
125134

135+
@abstractmethod
136+
def conversation(self) -> Conversation:
137+
"""
138+
当前进行中的会话.
139+
"""
140+
pass
141+
142+
@abstractmethod
143+
def convos(self) -> ConversationStore:
144+
"""
145+
当前 Ghost 实例下存储的会话历史.
146+
"""
147+
pass
148+
126149
def mindflow(self) -> Mindflow | None:
127150
"""
128151
Ghost 定义自身的 Mindflow. 如果返回 None 的话, 会使用 MOSS 架构提供的默认 mindflow 实现.
@@ -131,7 +154,7 @@ def mindflow(self) -> Mindflow | None:
131154
return None
132155

133156
@abstractmethod
134-
def articulate(self, context: ArticulateContext) -> Logos:
157+
def articulate(self, articulator: Articulator) -> Logos:
135158
"""
136159
articulate the logos from context
137160
"""

0 commit comments

Comments
 (0)