天枢 · Tianshu
· ───────────── ◆
│ │
· ───────────── ·
· ── · ── ·
Tianshu (天枢, Celestial Pivot) is the first star of the Big Dipper — the fixed point around which the northern sky revolves.
An AI code agent that thinks, plans, and acts. Give it a task; watch the loop turn.
天枢(天上的枢轴)是北斗七星第一星——北方星空围绕其旋转的固定点。
一个会思考、规划、执行的 AI 代码 Agent。给它一个任务,看循环运转。
Installation
pip install tianshu
Setup
Create a .env file in your project root:
ANTHROPIC_API_KEY=your_key
ANTHROPIC_BASE_URL=https://api.anthropic.com # optional, defaults to official API
Then start the agent:
ts
Features
- Chat mode: multi-turn conversation with full context
- Auto plan: the model decides whether to decompose complex tasks — no manual trigger needed
- Skills: predefined step sequences for common workflows; auto-matched by semantics or triggered manually with
/skill-name - Tool use: read/write files, run shell commands, search code, fetch web pages
- Long-term memory: important information is persisted and loaded on next startup
- Context compression: long conversations are compressed automatically to stay within the context window
Project Structure
tianshu/
├── main.py # CLI entry point, banner, input loop
└── agent/
├── __init__.py # re-exports Agent
├── core.py # Agent class: chat / execute / execute_skill, system prompt builder
├── planner/
│ ├── __init__.py # re-exports Planner, PlanExecutor, Replanner
│ └── core.py # goal decomposition, parallel execution, dynamic replanning
├── tools/
│ ├── __init__.py # re-exports TOOLS, TOOL_MAP, Tool
│ └── core.py # 12 built-in tools
├── skills/
│ ├── __init__.py # re-exports Skill, SkillLoader
│ ├── core.py # Skill dataclass + SkillLoader (load / match / find)
│ └── builtin/ # built-in skill YAMLs (run_and_fix_tests, code_review)
└── memory/
├── __init__.py # re-exports ContextManager, LongTermMemory
├── context.py # ContextManager: conversation compression
└── longterm.py # LongTermMemory: persisted to .agent/memory.md
Chat mode
user input
│
▼
Agent.chat()
│
├─ System prompt (built once at init, reused across turns)
│ ├── base instructions (role, tool-use principles)
│ ├── project type detection (pyproject.toml / package.json / go.mod …)
│ ├── top-level directory listing (up to 40 entries)
│ ├── repo outline (all def / class with line numbers)
│ ├── git status & branch
│ ├── long-term memory (.agent/memory.md, if present)
│ └── conversation summary (generated by ContextManager after compression)
│
├─ ContextManager.maybe_compress()
│ └── estimates token count; if over 60k:
│ └── LLM compresses old messages into a summary, keeps last 4 turns
│
└─ Tool-use loop (up to 10 iterations)
│
├── API call (history + 12 tool schemas)
│
├── stop_reason = end_turn ──→ return text to user
│
└── stop_reason = tool_use
├── file ops read_file / write_file / edit_file / create_directory
├── code nav get_outline / find_symbol / grep_files / list_files
├── shell bash
├── web web_search / web_fetch
└── memory save_memory
│
└── truncated tool result appended to history → next iteration
Plan mode (auto-triggered or /skill-name)
user input
│
├─ starts with / → SkillLoader.find() → exact skill match → Agent.execute_skill()
│
└─ plain input → Agent.execute()
│
├─ SkillLoader.match() (semantic match) → hit → use predefined steps directly
│
└─ Planner.decompose() (LLM decides)
├─ needs_plan=false → Agent.chat() (plain conversation)
└─ needs_plan=true → Plan { steps: [...] }
│
▼
PlanExecutor.execute()
│
├── create shared workspace .agent/workspace/<uuid>/
│
├─ scheduling loop (ThreadPoolExecutor, max_workers=4)
│ └── find all steps whose depends_on are satisfied, submit concurrently
│
├─ each step (independent Agent)
│ ├── new Agent instance (reuses parent system prompt)
│ ├── prompt: overall goal + current step + prerequisite output file paths
│ └── Agent.chat() → full tool-use loop → record result
│
├─ on step failure → Replanner.replan()
│ └── LLM decides: skip / retry (new description) / replace remaining steps
│
└── summary: all done → output summary / partial failure → list failed steps
Agent iteration plan
Phase 1: Basic agent (complete)
What: custom tool system, ReAct loop, memory management.
Why: a useful agent needs three primitives — access to the outside world (tools), multi-step reasoning (ReAct loop), and cross-turn memory (short-term compression + long-term persistence). None of these is optional: without tools the agent can only talk, without a loop it cannot handle complex tasks, without memory every conversation starts from zero.
Key components:
tools/core.py: 12 built-in tools (file I/O, code navigation, bash, web, memory)agent/core.py: ReAct loop, up to 10 iterations, per-tool result truncation to prevent context overflowmemory/context.py: short-term memory — compresses conversation history when it exceeds 60k tokensmemory/longterm.py: long-term memory — persisted to.agent/memory.md, injected into system prompt on startup
Phase 2: Plan mode (complete)
What: Planner (goal decomposition) + PlanExecutor (per-step independent execution).
Why: the ReAct loop has two hard limits. First, _MAX_ITERATIONS = 10 — complex tasks need far more than 10 tool calls. Second, history grows unboundedly — a multi-step task inflates context until the model "forgets" earlier work. Plan mode solves this with divide-and-conquer: one LLM call decomposes the goal into 3–8 steps, then each step runs in its own Agent with its own history.
Key components:
Planner.decompose(): single LLM call, outputs a step listPlanExecutor.execute(): instantiates an independent Agent per step, passes the previous step's result (first 200 chars) as context
Phase 3: Multi-agent orchestration (complete)
What: parallel execution (DAG dependencies), shared workspace, dynamic replanning.
Why: phase 2 steps were strictly sequential — even independent steps had to wait for each other. Real tasks (e.g. "analyze 5 files and summarize") can run concurrently. Also, 200-char summaries are too small to share large artifacts between steps. And abandoning the entire plan on a single failure is too costly — the model should decide how to recover.
New capabilities:
- Parallel execution:
Step.depends_ondefines a DAG;ThreadPoolExecutorruns all steps whose dependencies are satisfied concurrently - Shared workspace: each plan creates
.agent/workspace/<uuid>/; steps write files there and downstream steps read them by path - Dynamic replanning: on step failure,
Replannerasks the LLM toskip/retry/replaceremaining steps (up to 3 times)
Phase 4: Auto plan triggering and skills (complete)
What: remove the explicit /plan command; introduce a reusable skill system.
Why removing /plan: it exposes an internal implementation detail. Complexity judgment is the model's responsibility, not the user's. Planner now includes a needs_plan field in its prompt — the model returns None for simple tasks (falls back to chat()) or a Plan for complex ones, transparently.
Why skills: high-frequency workflows (e.g. "run tests and fix failures", "review recent changes") had to be re-planned from scratch every time, wasting tokens and risking inconsistent plans. Skills are predefined step sequences stored as YAML — they can be auto-matched when the user's input is semantically close, or triggered precisely with /skill-name.
Key components:
Skill: pure data class withname,description,stepsSkillLoader: loadsbuiltin/*.yaml; providesfind()(exact match) andmatch()(single LLM semantic match)Planner.decompose(): tries skill match first; falls back to LLM planning; returnsNoneifneeds_plan=falseAgent.execute_skill(): converts Skill → Plan → PlanExecutor;main.pystays unaware of internals
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file tsagent-0.3.0.tar.gz.
File metadata
- Download URL: tsagent-0.3.0.tar.gz
- Upload date:
- Size: 26.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.11.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b8eb91d97751470dc15ff740fc5c62696340a54c75312067a28c63db36a80c88
|
|
| MD5 |
5685b8ad5539912f2da6d1cf210208be
|
|
| BLAKE2b-256 |
2c72968c69bb25745a4dc8a6d9d2450800ee3b694d60bb7f4f92222d682b4204
|
File details
Details for the file tsagent-0.3.0-py3-none-any.whl.
File metadata
- Download URL: tsagent-0.3.0-py3-none-any.whl
- Upload date:
- Size: 21.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.11.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
aecfecfb64b23cb5ae892288da09097370ccf48d534ca2dd39747c0bb4b7023d
|
|
| MD5 |
c95944a8de18a25a2c6d2f0944921b34
|
|
| BLAKE2b-256 |
c9565408b53b8cad7b568d66550ff2633641f55a435dd02368f3f3c764bc103a
|