Skip to main content

天枢 · 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 overflow
  • memory/context.py: short-term memory — compresses conversation history when it exceeds 60k tokens
  • memory/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 list
  • PlanExecutor.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_on defines a DAG; ThreadPoolExecutor runs 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, Replanner asks the LLM to skip / retry / replace remaining 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 with name, description, steps
  • SkillLoader: loads builtin/*.yaml; provides find() (exact match) and match() (single LLM semantic match)
  • Planner.decompose(): tries skill match first; falls back to LLM planning; returns None if needs_plan=false
  • Agent.execute_skill(): converts Skill → Plan → PlanExecutor; main.py stays 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

tsagent-0.3.0.tar.gz (26.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

tsagent-0.3.0-py3-none-any.whl (21.8 kB view details)

Uploaded Python 3

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

Hashes for tsagent-0.3.0.tar.gz
Algorithm Hash digest
SHA256 b8eb91d97751470dc15ff740fc5c62696340a54c75312067a28c63db36a80c88
MD5 5685b8ad5539912f2da6d1cf210208be
BLAKE2b-256 2c72968c69bb25745a4dc8a6d9d2450800ee3b694d60bb7f4f92222d682b4204

See more details on using hashes here.

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

Hashes for tsagent-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 aecfecfb64b23cb5ae892288da09097370ccf48d534ca2dd39747c0bb4b7023d
MD5 c95944a8de18a25a2c6d2f0944921b34
BLAKE2b-256 c9565408b53b8cad7b568d66550ff2633641f55a435dd02368f3f3c764bc103a

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page