noosphere 0.1.2 → 0.1.3

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.
Files changed (2) hide show
  1. package/README.md +476 -37
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -478,68 +478,507 @@ A unified gateway that routes to 8 LLM providers through 4 different API protoco
478
478
 
479
479
  Aggregator providing access to hundreds of additional models including Llama, Deepseek, Mistral, Qwen, and many more. Full list available via `ai.getModels('llm')`.
480
480
 
481
- #### Agentic Capabilities (via Pi-AI library)
481
+ #### The Pi-AI Engine — Deep Dive
482
482
 
483
- The underlying `@mariozechner/pi-ai` library exposes powerful agentic features. While Noosphere currently surfaces chat and streaming, the library provides:
483
+ Noosphere's LLM provider is powered by `@mariozechner/pi-ai`, part of the **Pi mono-repo** by Mario Zechner (badlogic). Pi is NOT a wrapper like LangChain or Mastra — it's a **micro-framework for agentic AI** (~15K LOC, 4 npm packages) that was built from scratch as a minimalist alternative to Claude Code.
484
+
485
+ Pi consists of 4 packages in 3 tiers:
486
+
487
+ ```
488
+ TIER 1 — FOUNDATION
489
+ @mariozechner/pi-ai LLM API: stream(), complete(), model registry
490
+ 0 internal deps, talks to 20+ providers
491
+
492
+ TIER 2 — INFRASTRUCTURE
493
+ @mariozechner/pi-agent-core Agent loop, tool execution, lifecycle events
494
+ Depends on pi-ai
495
+
496
+ @mariozechner/pi-tui Terminal UI with differential rendering
497
+ Standalone, 0 internal deps
498
+
499
+ TIER 3 — APPLICATION
500
+ @mariozechner/pi-coding-agent CLI + SDK: sessions, compaction, extensions
501
+ Depends on all above
502
+ ```
503
+
504
+ Noosphere uses `@mariozechner/pi-ai` (Tier 1) directly for LLM access. But the full Pi ecosystem provides capabilities that can be layered on top.
505
+
506
+ ---
507
+
508
+ #### How Pi Keeps 200+ Models Updated
509
+
510
+ Pi does NOT hardcode models. It has an **auto-generation pipeline** that runs at build time:
511
+
512
+ ```
513
+ STEP 1: FETCH (3 sources in parallel)
514
+ ┌──────────────────┐ ┌──────────────────┐ ┌───────────────┐
515
+ │ models.dev │ │ OpenRouter │ │ Vercel AI │
516
+ │ /api.json │ │ /v1/models │ │ Gateway │
517
+ │ │ │ │ │ /v1/models │
518
+ │ Context windows │ │ Pricing ($/M) │ │ Capability │
519
+ │ Capabilities │ │ Availability │ │ tags │
520
+ │ Tool support │ │ Provider routing │ │ │
521
+ └────────┬─────────┘ └────────┬─────────┘ └──────┬────────┘
522
+ └─────────┬───────────┴────────────────────┘
523
+
524
+ STEP 2: MERGE & DEDUPLICATE
525
+ Priority: models.dev > OpenRouter > Vercel
526
+ Key: provider + modelId
527
+
528
+
529
+ STEP 3: FILTER
530
+ ✅ tool_call === true
531
+ ✅ streaming supported
532
+ ✅ system messages supported
533
+ ✅ not deprecated
534
+
535
+
536
+ STEP 4: NORMALIZE
537
+ Costs → $/million tokens
538
+ API type → one of 4 protocols
539
+ Input modes → ["text"] or ["text","image"]
540
+
541
+
542
+ STEP 5: PATCH (manual corrections)
543
+ Claude Opus: cache pricing fix
544
+ GPT-5.4: context window override
545
+ Kimi K2.5: hardcoded pricing
546
+
547
+
548
+ STEP 6: GENERATE TypeScript
549
+ → models.generated.ts (~330KB)
550
+ → 200+ models with full type safety
551
+ ```
552
+
553
+ Each generated model entry looks like:
554
+
555
+ ```typescript
556
+ {
557
+ id: "claude-opus-4-6",
558
+ name: "Claude Opus 4.6",
559
+ api: "anthropic-messages",
560
+ provider: "anthropic",
561
+ baseUrl: "https://api.anthropic.com",
562
+ reasoning: true,
563
+ input: ["text", "image"],
564
+ cost: {
565
+ input: 15, // $15/M tokens
566
+ output: 75, // $75/M tokens
567
+ cacheRead: 1.5, // prompt cache hit
568
+ cacheWrite: 18.75, // prompt cache write
569
+ },
570
+ contextWindow: 200_000,
571
+ maxTokens: 32_000,
572
+ } satisfies Model<"anthropic-messages">
573
+ ```
574
+
575
+ When a new model is released (e.g., Gemini 3.0), it appears in models.dev/OpenRouter → the script captures it → a new Pi version is published → Noosphere updates its dependency.
576
+
577
+ ---
578
+
579
+ #### 4 API Protocols — How Pi Talks to Every Provider
580
+
581
+ Pi abstracts all LLM providers into 4 wire protocols. Each protocol handles the differences in request format, streaming format, auth headers, and response parsing:
582
+
583
+ | Protocol | Providers | Key Differences |
584
+ |---|---|---|
585
+ | `anthropic-messages` | Anthropic, AWS Bedrock | `system` as top-level field, content as `[{type:"text", text:"..."}]` blocks, `x-api-key` auth, `anthropic-beta` headers |
586
+ | `openai-completions` | OpenAI, xAI, Groq, Cerebras, OpenRouter, Ollama, vLLM | `system` as message with `role:"system"`, content as string, `Authorization: Bearer` auth, `tool_calls` array |
587
+ | `openai-responses` | OpenAI (reasoning models) | New Responses API with server-side context, `store: true`, reasoning summaries |
588
+ | `google-generative-ai` | Google Gemini, Vertex AI | `systemInstruction.parts[{text}]`, role `"model"` instead of `"assistant"`, `functionCall` instead of `tool_calls`, `thinkingConfig` |
589
+
590
+ The core function `streamSimple()` detects which protocol to use based on `model.api` and handles all the formatting/parsing transparently:
484
591
 
485
- **Tool Use / Function Calling:**
486
592
  ```typescript
487
- // Supported across Anthropic, OpenAI, Google, xAI, Groq
488
- // Tool definitions use TypeBox schemas for runtime validation
489
- interface Tool<TParameters extends TSchema = TSchema> {
490
- name: string;
491
- description: string;
492
- parameters: TParameters; // TypeBox schema — validated at runtime with AJV
593
+ // What happens inside Pi when you call Noosphere's chat():
594
+ async function* streamSimple(
595
+ model: Model, // includes model.api to determine protocol
596
+ context: Context, // { systemPrompt, messages, tools }
597
+ options?: StreamOptions // { signal, onPayload, thinkingLevel, ... }
598
+ ): AsyncIterable<AssistantMessageEvent> {
599
+ // 1. Format request according to model.api protocol
600
+ // 2. Open SSE/WebSocket stream
601
+ // 3. Parse provider-specific chunks
602
+ // 4. Emit normalized events:
603
+ // → text_delta, thinking_delta, tool_call, message_end
493
604
  }
494
605
  ```
495
606
 
496
- **Reasoning / Thinking:**
497
- - **Anthropic:** `thinkingEnabled`, `thinkingBudgetTokens` — Claude Opus/Sonnet extended thinking
498
- - **OpenAI:** `reasoningEffort` (minimal/low/medium/high) — o1/o3/o4/GPT-5 reasoning
499
- - **Google:** `thinking.enabled`, `thinking.budgetTokens` — Gemini 2.5 thinking
500
- - **xAI:** Grok-4 native reasoning
501
- - Thinking blocks are automatically extracted and streamed as separate `thinking_delta` events
607
+ ---
608
+
609
+ #### Agentic Capabilities
610
+
611
+ These are the capabilities people get access to through the Pi-AI engine:
612
+
613
+ ##### 1. Tool Use / Function Calling
614
+
615
+ Full structured tool calling supported across **all major providers**. Tool definitions use TypeBox schemas with runtime validation via AJV:
616
+
617
+ ```typescript
618
+ import { type Tool, StringEnum } from '@mariozechner/pi-ai';
619
+ import { Type } from '@sinclair/typebox';
620
+
621
+ // Define a tool with typed parameters
622
+ const searchTool: Tool = {
623
+ name: 'web_search',
624
+ description: 'Search the web for information',
625
+ parameters: Type.Object({
626
+ query: Type.String({ description: 'Search query' }),
627
+ maxResults: Type.Optional(Type.Number({ default: 5 })),
628
+ type: StringEnum(['web', 'images', 'news'], { description: 'Search type' }),
629
+ }),
630
+ };
631
+
632
+ // Pass tools in context — Pi handles the rest
633
+ const context = {
634
+ systemPrompt: 'You are a helpful assistant.',
635
+ messages: [{ role: 'user', content: 'Search for recent AI news' }],
636
+ tools: [searchTool],
637
+ };
638
+ ```
639
+
640
+ **How tool calling works internally:**
641
+
642
+ ```
643
+ User prompt → LLM → "I need to call web_search"
644
+
645
+
646
+ Pi validates arguments with AJV
647
+ against the TypeBox schema
648
+
649
+ ┌─────┴─────┐
650
+ │ Valid? │
651
+ ├─Yes───────┤
652
+ │ Execute │
653
+ │ tool │
654
+ ├───────────┤
655
+ │ No │
656
+ │ Return │
657
+ │ validation│
658
+ │ error to │
659
+ │ LLM │
660
+ └───────────┘
661
+
662
+
663
+ Tool result → back into context → LLM continues
664
+ ```
665
+
666
+ **Provider-specific tool_choice control:**
667
+ - **Anthropic:** `"auto" | "any" | "none" | { type: "tool", name: "specific_tool" }`
668
+ - **OpenAI:** `"auto" | "none" | "required" | { type: "function", function: { name: "..." } }`
669
+ - **Google:** `"auto" | "none" | "any"`
670
+
671
+ **Partial JSON streaming:** During streaming, Pi parses tool call arguments incrementally using partial JSON parsing. This means you can see tool arguments being built in real-time, not just after the tool call completes.
672
+
673
+ ##### 2. Reasoning / Extended Thinking
674
+
675
+ Pi provides **unified thinking support** across all providers that support it. Thinking blocks are automatically extracted, separated from regular text, and streamed as distinct events:
676
+
677
+ | Provider | Models | Control Parameters | How It Works |
678
+ |---|---|---|---|
679
+ | **Anthropic** | Claude Opus, Sonnet 4+ | `thinkingEnabled: boolean`, `thinkingBudgetTokens: number` | Extended thinking blocks in response, separate `thinking` content type |
680
+ | **OpenAI** | o1, o3, o4, GPT-5 | `reasoningEffort: "minimal" \| "low" \| "medium" \| "high"` | Reasoning via Responses API, `reasoningSummary: "auto" \| "detailed" \| "concise"` |
681
+ | **Google** | Gemini 2.5 Flash/Pro | `thinking.enabled: boolean`, `thinking.budgetTokens: number` | Thinking via `thinkingConfig`, mapped to effort levels |
682
+ | **xAI** | Grok-4, Grok-3-mini | Native reasoning | Automatic when model supports it |
683
+
684
+ **Cross-provider thinking portability:** When switching models mid-conversation, Pi converts thinking blocks between formats. Anthropic thinking blocks become `<thinking>` tagged text when sent to OpenAI/Google, and vice versa.
502
685
 
503
- **Vision / Multimodal Input:**
504
686
  ```typescript
505
- // Send images alongside text to vision-capable models
506
- {
507
- role: "user",
508
- content: [
509
- { type: "text", text: "What's in this image?" },
510
- { type: "image", data: base64String, mimeType: "image/png" }
511
- ]
687
+ // Thinking is automatically extracted in Noosphere responses:
688
+ const result = await ai.chat({
689
+ model: 'claude-opus-4-6',
690
+ messages: [{ role: 'user', content: 'Solve this step by step: 15! / 13!' }],
691
+ });
692
+
693
+ console.log(result.thinking); // "Let me work through this... 15! = 15 × 14 × 13!..."
694
+ console.log(result.content); // "15! / 13! = 15 × 14 = 210"
695
+
696
+ // During streaming, thinking arrives as separate events:
697
+ const stream = ai.stream({ messages: [...] });
698
+ for await (const event of stream) {
699
+ if (event.type === 'thinking_delta') console.log('[THINKING]', event.delta);
700
+ if (event.type === 'text_delta') console.log('[RESPONSE]', event.delta);
512
701
  }
513
702
  ```
514
703
 
515
- **Agent Loop:**
704
+ ##### 3. Vision / Multimodal Input
705
+
706
+ Models with `input: ["text", "image"]` accept images alongside text. Pi handles the encoding and format differences per provider:
707
+
708
+ ```typescript
709
+ // Send images to vision-capable models
710
+ const messages = [{
711
+ role: 'user',
712
+ content: [
713
+ { type: 'text', text: 'What is in this image?' },
714
+ { type: 'image', data: base64PngString, mimeType: 'image/png' },
715
+ ],
716
+ }];
717
+
718
+ // Supported MIME types: image/png, image/jpeg, image/gif, image/webp
719
+ // Images are silently ignored when sent to non-vision models
720
+ ```
721
+
722
+ **Vision-capable models include:** All Claude models, all GPT-4o/GPT-5 models, Gemini models, Grok-2-vision, Grok-4, and select Groq models.
723
+
724
+ ##### 4. Agent Loop — Autonomous Tool Execution
725
+
726
+ The `@mariozechner/pi-agent-core` package provides a complete agent loop that automatically cycles through `prompt → LLM → tool call → result → repeat` until the task is done:
727
+
516
728
  ```typescript
517
- // Built-in agentic execution loop with automatic tool calling
518
729
  import { agentLoop } from '@mariozechner/pi-ai';
519
730
 
520
- const events = agentLoop(prompt, context, {
521
- tools: [myTool],
522
- model: getModel('anthropic', 'claude-sonnet-4-20250514'),
731
+ const events = agentLoop(userMessage, agentContext, {
732
+ model: getModel('anthropic', 'claude-opus-4-6'),
733
+ tools: [searchTool, readFileTool, writeFileTool],
734
+ signal: abortController.signal,
523
735
  });
524
736
 
525
737
  for await (const event of events) {
526
- // event.type: agent_start → turn_start → message_start →
527
- // message_update tool_execution_start → tool_execution_end →
528
- // message_end turn_end agent_end
738
+ switch (event.type) {
739
+ case 'agent_start': // Agent begins
740
+ case 'turn_start': // New LLM turn begins
741
+ case 'message_start': // LLM starts responding
742
+ case 'message_update': // Text/thinking delta received
743
+ case 'tool_execution_start': // About to execute a tool
744
+ case 'tool_execution_end': // Tool finished, result available
745
+ case 'message_end': // LLM finished this message
746
+ case 'turn_end': // Turn complete (may loop if tools were called)
747
+ case 'agent_end': // All done, final messages available
748
+ }
529
749
  }
530
750
  ```
531
751
 
532
- **Cost Tracking per Model:**
752
+ **The agent loop state machine:**
753
+
754
+ ```
755
+ [User sends prompt]
756
+
757
+
758
+ ┌─[Build Context]──▶ [Check Queues]──▶ [Stream LLM]◄── streamFn()
759
+ │ │
760
+ │ ┌─────┴──────┐
761
+ │ │ │
762
+ │ text tool_call
763
+ │ │ │
764
+ │ ▼ ▼
765
+ │ [Done] [Execute Tool]
766
+ │ │
767
+ │ tool result
768
+ │ │
769
+ └──────────────────────────────────────────────────┘
770
+ (loops back to Stream LLM)
771
+ ```
772
+
773
+ **Key design decisions:**
774
+ - Tools execute **sequentially** by default (parallelism can be added on top)
775
+ - The `streamFn` is **injectable** — you can wrap it with middleware to modify requests per-provider
776
+ - Tool arguments are **validated at runtime** using TypeBox + AJV before execution
777
+ - Aborted/failed responses preserve partial content and usage data
778
+ - Tool results are automatically added to the conversation context
779
+
780
+ ##### 5. The `streamFn` Pattern — Injectable Middleware
781
+
782
+ This is Pi's most powerful architectural feature. The `streamFn` is the function that actually talks to the LLM, and it can be **wrapped with middleware** like Express.js request handlers:
783
+
784
+ ```typescript
785
+ import type { StreamFn } from '@mariozechner/pi-agent-core';
786
+ import { streamSimple } from '@mariozechner/pi-ai';
787
+
788
+ // Start with Pi's base streaming function
789
+ let fn: StreamFn = streamSimple;
790
+
791
+ // Wrap it with middleware that modifies requests per-provider
792
+ fn = createMyCustomWrapper(fn, {
793
+ // Add custom headers for Anthropic
794
+ onPayload: (payload) => {
795
+ if (model.provider === 'anthropic') {
796
+ payload.headers['anthropic-beta'] = 'fine-grained-tool-streaming-2025-05-14';
797
+ }
798
+ },
799
+ });
800
+
801
+ // Each wrapper calls the previous one, forming a chain:
802
+ // request → wrapper3 → wrapper2 → wrapper1 → streamSimple → API
803
+ ```
804
+
805
+ This pattern is what allows projects like OpenClaw to stack **16 provider-specific wrappers** on top of Pi's base streaming — adding beta headers for Anthropic, WebSocket transport for OpenAI, thinking sanitization for Google, reasoning effort headers for OpenRouter, and more — without modifying Pi's source code.
806
+
807
+ ##### 6. Session Management (via pi-coding-agent)
808
+
809
+ The `@mariozechner/pi-coding-agent` package provides persistent session management with JSONL-based storage:
810
+
533
811
  ```typescript
534
- // Costs tracked per 1M tokens with cache-aware pricing
812
+ import { createAgentSession, SessionManager } from '@mariozechner/pi-coding-agent';
813
+
814
+ // Create a session with full persistence
815
+ const session = await createAgentSession({
816
+ model: 'claude-opus-4-6',
817
+ tools: myTools,
818
+ sessionManager, // handles JSONL persistence
819
+ });
820
+
821
+ const result = await session.run('Build a REST API');
822
+ // Session is automatically saved to:
823
+ // ~/.pi/agent/sessions/session_abc123.jsonl
824
+ ```
825
+
826
+ **Session file format (append-only JSONL):**
827
+ ```jsonl
828
+ {"role":"user","content":"Build a REST API","timestamp":1710000000}
829
+ {"role":"assistant","content":"I'll create...","model":"claude-opus-4-6","usage":{...}}
830
+ {"role":"toolResult","toolCallId":"tc_001","toolName":"bash","content":"OK"}
831
+ {"type":"compaction","summary":"The user asked to build...","preservedMessages":[...]}
832
+ ```
833
+
834
+ **Session operations:**
835
+ - `create()` — new session
836
+ - `open(id)` — restore existing session
837
+ - `continueRecent()` — continue the most recent session
838
+ - `forkFrom(id)` — create a branch (new JSONL referencing parent)
839
+ - `inMemory()` — RAM-only session (for SDK/testing)
840
+
841
+ ##### 7. Context Compaction — Automatic Context Window Management
842
+
843
+ When the conversation approaches the model's context window limit, Pi automatically **compacts** the history:
844
+
845
+ ```
846
+ 1. DETECT: Calculate inputTokens + outputTokens vs model.contextWindow
847
+ 2. TRIGGER: Proactively before overflow, or as recovery after overflow error
848
+ 3. SUMMARIZE: Send history to LLM with a compaction prompt
849
+ 4. WRITE: Append compaction entry to JSONL:
850
+ {"type":"compaction","summary":"...","preservedMessages":[last N messages]}
851
+ 5. CONTINUE: Context is now summary + recent messages instead of full history
852
+ ```
853
+
854
+ The JSONL file is **never rewritten** — compaction entries are appended, maintaining a complete audit trail.
855
+
856
+ ##### 8. Cost Tracking — Cache-Aware Pricing
857
+
858
+ Pi tracks costs per-request with cache-aware pricing for providers that support prompt caching:
859
+
860
+ ```typescript
861
+ // Every model has 4 cost dimensions:
535
862
  {
536
- input: number, // cost per 1M input tokens
537
- output: number, // cost per 1M output tokens
538
- cacheRead: number, // prompt cache hit cost
539
- cacheWrite: number, // prompt cache write cost
863
+ input: 15, // $15 per 1M input tokens
864
+ output: 75, // $75 per 1M output tokens
865
+ cacheRead: 1.5, // $1.50 per 1M cached prompt tokens (read)
866
+ cacheWrite: 18.75, // $18.75 per 1M cached prompt tokens (write)
867
+ }
868
+
869
+ // Usage tracking on every response:
870
+ {
871
+ input: 1500, // tokens consumed as input
872
+ output: 800, // tokens generated
873
+ cacheRead: 5000, // prompt cache hits
874
+ cacheWrite: 1500, // prompt cache writes
875
+ cost: {
876
+ total: 0.082, // total cost in USD
877
+ input: 0.0225,
878
+ output: 0.06,
879
+ cacheRead: 0.0075,
880
+ cacheWrite: 0.028,
881
+ },
540
882
  }
541
883
  ```
542
884
 
885
+ **Anthropic and OpenAI** support prompt caching. For providers without caching, `cacheRead` and `cacheWrite` are always 0.
886
+
887
+ ##### 9. Extension System (via pi-coding-agent)
888
+
889
+ Pi supports a plugin system where extensions can register tools, commands, and lifecycle hooks:
890
+
891
+ ```typescript
892
+ // Extensions are TypeScript modules loaded at runtime via jiti
893
+ export default function(api: ExtensionAPI) {
894
+ // Register a custom tool
895
+ api.registerTool('my_tool', {
896
+ description: 'Does something useful',
897
+ parameters: { /* TypeBox schema */ },
898
+ execute: async (args) => 'result',
899
+ });
900
+
901
+ // Register a slash command
902
+ api.registerCommand('/mycommand', {
903
+ handler: async (args) => { /* ... */ },
904
+ description: 'Custom command',
905
+ });
906
+
907
+ // Hook into the agent lifecycle
908
+ api.on('before_agent_start', async (context) => {
909
+ context.systemPrompt += '\nExtra instructions';
910
+ });
911
+
912
+ api.on('tool_execution_end', async (event) => {
913
+ // Post-process tool results
914
+ });
915
+ }
916
+ ```
917
+
918
+ **Resource discovery chain (priority):**
919
+ 1. Project `.pi/` directory (highest)
920
+ 2. User `~/.pi/agent/`
921
+ 3. npm packages with Pi metadata
922
+ 4. Built-in defaults
923
+
924
+ ##### 10. The Anti-MCP Philosophy — Why Pi Uses CLI Instead
925
+
926
+ Pi explicitly **rejects MCP** (Model Context Protocol). Mario Zechner's argument, backed by benchmarks:
927
+
928
+ **The token cost problem:**
929
+
930
+ | Approach | Tools | Tokens Consumed | % of Claude's Context |
931
+ |---|---|---|---|
932
+ | Playwright MCP | 21 tools | 13,700 tokens | 6.8% |
933
+ | Chrome DevTools MCP | 26 tools | 18,000 tokens | 9.0% |
934
+ | Pi CLI + README | N/A | 225 tokens | ~0.1% |
935
+
936
+ That's a **60-80x reduction** in token consumption. With 5 MCP servers, you lose ~55,000 tokens before doing any work.
937
+
938
+ **Benchmark results (120 evaluations):**
939
+
940
+ | Approach | Avg Cost | Success Rate |
941
+ |---|---|---|
942
+ | CLI (tmux) | $0.37 | 100% |
943
+ | CLI (terminalcp) | $0.39 | 100% |
944
+ | MCP (terminalcp) | $0.48 | 100% |
945
+
946
+ Same success rate, MCP costs **30% more**.
947
+
948
+ **Pi's alternative: Progressive Disclosure via CLI tools + READMEs**
949
+
950
+ Instead of loading all tool definitions upfront, Pi's agent has `bash` as a built-in tool and discovers CLI tools only when needed:
951
+
952
+ ```
953
+ MCP approach: Pi approach:
954
+ ───────────── ──────────
955
+ Session start → Session start →
956
+ Load 21 Playwright tools Load 4 tools: read, write, edit, bash
957
+ Load 26 Chrome DevTools tools (225 tokens)
958
+ Load N more MCP tools
959
+ (~55,000 tokens wasted)
960
+
961
+ When browser needed: When browser needed:
962
+ Tools already loaded Agent reads SKILL.md (225 tokens)
963
+ (but context is polluted) Runs: browser-start.js
964
+ Runs: browser-nav.js https://...
965
+ Runs: browser-screenshot.js
966
+
967
+ When browser NOT needed: When browser NOT needed:
968
+ Tools still consume context 0 tokens wasted
969
+ ```
970
+
971
+ **The 4 built-in tools** (what Pi argues is sufficient):
972
+
973
+ | Tool | What It Does | Why It's Enough |
974
+ |---|---|---|
975
+ | `read` | Read files (text + images) | Supports offset/limit for large files |
976
+ | `write` | Create/overwrite files | Creates directories automatically |
977
+ | `edit` | Replace text (oldText→newText) | Surgical edits, like a diff |
978
+ | `bash` | Execute any shell command | **bash can do everything else** — replaces MCP entirely |
979
+
980
+ The key insight: `bash` replaces MCP. Any CLI tool, API call, database query, or system operation can be invoked through bash. The agent reads the tool's README only when it needs it, paying tokens on-demand instead of upfront.
981
+
543
982
  ---
544
983
 
545
984
  ### FAL — Media Generation (867+ endpoints)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "noosphere",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Unified AI creation engine — text, image, video, audio across all providers",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",