noosphere 0.9.2 → 0.9.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.
- package/README.md +159 -13
- package/package.json +31 -4
package/README.md
CHANGED
|
@@ -694,35 +694,181 @@ const claude = await countTokensAnthropic(messages, ANTHROPIC_KEY, 'claude-sonne
|
|
|
694
694
|
|
|
695
695
|
## Agent Loop & pi-ai Access
|
|
696
696
|
|
|
697
|
-
Noosphere re-exports the full [pi-ai](https://github.com/
|
|
697
|
+
Noosphere re-exports the full [pi-ai](https://github.com/mariozechner/pi-ai) library for direct access to agent loops, tool calling, cost calculation, and streaming APIs.
|
|
698
|
+
|
|
699
|
+
### Preprocessor — Context Compaction
|
|
700
|
+
|
|
701
|
+
The preprocessor hook runs **before every LLM call** in the agent loop. Use it to manage context window limits — truncate old messages, summarize conversations, or implement sliding window strategies.
|
|
698
702
|
|
|
699
703
|
```typescript
|
|
700
|
-
import {
|
|
701
|
-
|
|
702
|
-
piStream, piComplete, piStreamSimple, piCompleteSimple,
|
|
703
|
-
setApiKey, getApiKey, getPiModel, getPiModels, getPiProviders,
|
|
704
|
-
} from 'noosphere';
|
|
704
|
+
import { agentLoop, getPiModel, setApiKey, countTokensOpenAI } from 'noosphere';
|
|
705
|
+
import type { AgentLoopConfig, AgentContext, PiMessage } from 'noosphere';
|
|
705
706
|
|
|
706
|
-
|
|
707
|
-
import type { AgentLoopConfig, AgentContext, AgentTool } from 'noosphere';
|
|
707
|
+
setApiKey('openai', process.env.OPENAI_API_KEY!);
|
|
708
708
|
|
|
709
709
|
const config: AgentLoopConfig = {
|
|
710
710
|
model: getPiModel('openai', 'gpt-4o'),
|
|
711
|
-
|
|
711
|
+
|
|
712
|
+
// Preprocessor runs before each LLM call
|
|
712
713
|
preprocessor: async (messages) => {
|
|
713
|
-
//
|
|
714
|
+
// Strategy 1: Simple sliding window — keep last N messages
|
|
714
715
|
if (messages.length > 50) {
|
|
715
|
-
return messages.slice(-20);
|
|
716
|
+
return messages.slice(-20);
|
|
716
717
|
}
|
|
717
718
|
return messages;
|
|
718
719
|
},
|
|
719
720
|
};
|
|
720
721
|
|
|
721
|
-
//
|
|
722
|
+
// Start the agent loop
|
|
723
|
+
const context: AgentContext = {
|
|
724
|
+
systemPrompt: 'You are a helpful assistant.',
|
|
725
|
+
messages: [],
|
|
726
|
+
};
|
|
727
|
+
|
|
728
|
+
const userMessage = {
|
|
729
|
+
role: 'user' as const,
|
|
730
|
+
content: 'Hello!',
|
|
731
|
+
timestamp: Date.now(),
|
|
732
|
+
};
|
|
733
|
+
|
|
734
|
+
const stream = agentLoop(userMessage, context, config);
|
|
735
|
+
|
|
736
|
+
for await (const event of stream) {
|
|
737
|
+
if (event.type === 'message_update' && event.assistantMessageEvent.type === 'text_delta') {
|
|
738
|
+
process.stdout.write(event.assistantMessageEvent.delta);
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
```
|
|
742
|
+
|
|
743
|
+
#### Preprocessor Strategies
|
|
744
|
+
|
|
745
|
+
**Token-aware compaction** — count tokens and trim to fit the context window:
|
|
746
|
+
|
|
747
|
+
```typescript
|
|
748
|
+
preprocessor: async (messages) => {
|
|
749
|
+
const model = getPiModel('openai', 'gpt-4o');
|
|
750
|
+
const maxTokens = model.contextWindow * 0.8; // leave 20% for response
|
|
751
|
+
|
|
752
|
+
let totalTokens = 0;
|
|
753
|
+
const kept: PiMessage[] = [];
|
|
754
|
+
|
|
755
|
+
// Keep messages from newest to oldest until we hit the limit
|
|
756
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
757
|
+
const msg = messages[i];
|
|
758
|
+
const content = 'content' in msg && typeof msg.content === 'string' ? msg.content : '';
|
|
759
|
+
const msgTokens = countTokensOpenAI([{ role: msg.role, content }], 'gpt-4o');
|
|
760
|
+
|
|
761
|
+
if (totalTokens + msgTokens > maxTokens) break;
|
|
762
|
+
totalTokens += msgTokens;
|
|
763
|
+
kept.unshift(msg);
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
return kept;
|
|
767
|
+
},
|
|
768
|
+
```
|
|
769
|
+
|
|
770
|
+
**Summarization compaction** — summarize old messages, keep recent ones:
|
|
771
|
+
|
|
772
|
+
```typescript
|
|
773
|
+
preprocessor: async (messages) => {
|
|
774
|
+
if (messages.length <= 20) return messages;
|
|
775
|
+
|
|
776
|
+
// Summarize the older messages using the LLM itself
|
|
777
|
+
const oldMessages = messages.slice(0, -10);
|
|
778
|
+
const recentMessages = messages.slice(-10);
|
|
779
|
+
|
|
780
|
+
const summary = await piCompleteSimple(getPiModel('openai', 'gpt-4o-mini'), {
|
|
781
|
+
systemPrompt: 'Summarize this conversation in 2-3 sentences.',
|
|
782
|
+
messages: oldMessages,
|
|
783
|
+
});
|
|
784
|
+
|
|
785
|
+
// Replace old messages with a summary message
|
|
786
|
+
const summaryText = summary.content
|
|
787
|
+
.filter((c): c is { type: 'text'; text: string } => c.type === 'text')
|
|
788
|
+
.map((c) => c.text)
|
|
789
|
+
.join('');
|
|
790
|
+
|
|
791
|
+
return [
|
|
792
|
+
{ role: 'user' as const, content: `[Previous conversation summary: ${summaryText}]`, timestamp: Date.now() },
|
|
793
|
+
...recentMessages,
|
|
794
|
+
];
|
|
795
|
+
},
|
|
796
|
+
```
|
|
797
|
+
|
|
798
|
+
### Tool Calling
|
|
799
|
+
|
|
800
|
+
Define tools for the agent loop with typed parameters:
|
|
801
|
+
|
|
802
|
+
```typescript
|
|
803
|
+
import { Type } from '@sinclair/typebox';
|
|
804
|
+
import type { AgentTool } from 'noosphere';
|
|
805
|
+
|
|
806
|
+
const weatherTool: AgentTool = {
|
|
807
|
+
name: 'get_weather',
|
|
808
|
+
label: 'Get Weather',
|
|
809
|
+
description: 'Get the current weather for a location',
|
|
810
|
+
parameters: Type.Object({
|
|
811
|
+
location: Type.String({ description: 'City name' }),
|
|
812
|
+
}),
|
|
813
|
+
execute: async (toolCallId, params) => {
|
|
814
|
+
const weather = await fetchWeather(params.location);
|
|
815
|
+
return { output: JSON.stringify(weather), details: weather };
|
|
816
|
+
},
|
|
817
|
+
};
|
|
818
|
+
|
|
819
|
+
const context: AgentContext = {
|
|
820
|
+
systemPrompt: 'You are a helpful assistant with weather access.',
|
|
821
|
+
messages: [],
|
|
822
|
+
tools: [weatherTool],
|
|
823
|
+
};
|
|
824
|
+
|
|
825
|
+
const stream = agentLoop(userMessage, context, config);
|
|
826
|
+
|
|
827
|
+
for await (const event of stream) {
|
|
828
|
+
if (event.type === 'tool_execution_start') {
|
|
829
|
+
console.log(`Calling ${event.toolName}...`);
|
|
830
|
+
}
|
|
831
|
+
if (event.type === 'tool_execution_end') {
|
|
832
|
+
console.log(`Result: ${event.result}`);
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
```
|
|
836
|
+
|
|
837
|
+
### Cost Calculation
|
|
838
|
+
|
|
839
|
+
```typescript
|
|
840
|
+
import { calculateCost, getPiModel } from 'noosphere';
|
|
841
|
+
|
|
722
842
|
const model = getPiModel('openai', 'gpt-4o');
|
|
723
843
|
const usage = { input: 1000, output: 500, cacheRead: 0, cacheWrite: 0 };
|
|
724
844
|
const cost = calculateCost(model, usage);
|
|
725
|
-
console.log(cost.total);
|
|
845
|
+
console.log(cost.total); // $0.00625
|
|
846
|
+
console.log(cost.input); // $0.0025
|
|
847
|
+
console.log(cost.output); // $0.00375
|
|
848
|
+
```
|
|
849
|
+
|
|
850
|
+
### Direct Stream/Complete APIs
|
|
851
|
+
|
|
852
|
+
```typescript
|
|
853
|
+
import { piComplete, piStream, piCompleteSimple, setApiKey, getPiModel } from 'noosphere';
|
|
854
|
+
|
|
855
|
+
setApiKey('openai', process.env.OPENAI_API_KEY!);
|
|
856
|
+
const model = getPiModel('openai', 'gpt-4o');
|
|
857
|
+
|
|
858
|
+
// Simple completion
|
|
859
|
+
const result = await piCompleteSimple(model, {
|
|
860
|
+
systemPrompt: 'You are helpful.',
|
|
861
|
+
messages: [{ role: 'user', content: 'Hello!', timestamp: Date.now() }],
|
|
862
|
+
});
|
|
863
|
+
|
|
864
|
+
// Streaming
|
|
865
|
+
const stream = piStream(model, {
|
|
866
|
+
messages: [{ role: 'user', content: 'Hello!', timestamp: Date.now() }],
|
|
867
|
+
});
|
|
868
|
+
|
|
869
|
+
for await (const event of stream) {
|
|
870
|
+
if (event.type === 'text_delta') process.stdout.write(event.delta);
|
|
871
|
+
}
|
|
726
872
|
```
|
|
727
873
|
|
|
728
874
|
---
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "noosphere",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.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",
|
|
@@ -41,17 +41,44 @@
|
|
|
41
41
|
"typescript": "^5.6.3",
|
|
42
42
|
"vitest": "^2.1.3"
|
|
43
43
|
},
|
|
44
|
+
"repository": {
|
|
45
|
+
"type": "git",
|
|
46
|
+
"url": "git+https://github.com/0xJesus/noosphere.git"
|
|
47
|
+
},
|
|
48
|
+
"homepage": "https://github.com/0xJesus/noosphere#readme",
|
|
49
|
+
"bugs": {
|
|
50
|
+
"url": "https://github.com/0xJesus/noosphere/issues"
|
|
51
|
+
},
|
|
44
52
|
"keywords": [
|
|
45
53
|
"ai",
|
|
46
54
|
"llm",
|
|
47
55
|
"image-generation",
|
|
48
|
-
"tts",
|
|
49
56
|
"video-generation",
|
|
57
|
+
"tts",
|
|
58
|
+
"stt",
|
|
59
|
+
"music-generation",
|
|
50
60
|
"openai",
|
|
51
61
|
"anthropic",
|
|
52
|
-
"
|
|
62
|
+
"google",
|
|
63
|
+
"gemini",
|
|
64
|
+
"dall-e",
|
|
65
|
+
"gpt-image",
|
|
66
|
+
"sora",
|
|
67
|
+
"imagen",
|
|
68
|
+
"veo",
|
|
69
|
+
"whisper",
|
|
53
70
|
"ollama",
|
|
54
|
-
"comfyui"
|
|
71
|
+
"comfyui",
|
|
72
|
+
"fal",
|
|
73
|
+
"huggingface",
|
|
74
|
+
"groq",
|
|
75
|
+
"mistral",
|
|
76
|
+
"xai",
|
|
77
|
+
"cerebras",
|
|
78
|
+
"openrouter",
|
|
79
|
+
"token-counting",
|
|
80
|
+
"agent-loop",
|
|
81
|
+
"multimodal"
|
|
55
82
|
],
|
|
56
83
|
"author": "0xJesus",
|
|
57
84
|
"license": "MIT"
|