@saadnvd1/agent-os 0.3.472 → 0.3.474
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/lib/agents/launch.ts +10 -1
- package/lib/chat/driver.ts +3 -0
- package/lib/chat/drivers/claude.ts +1 -0
- package/lib/chat/refresh.ts +29 -3
- package/lib/chat/worker/host.ts +9 -2
- package/lib/models/config.ts +1 -0
- package/lib/models/providers.ts +8 -0
- package/lib/models/resolve.ts +3 -0
- package/lib/orchestrator/tool-schemas.ts +9 -4
- package/package.json +1 -1
package/lib/agents/launch.ts
CHANGED
|
@@ -52,6 +52,14 @@ export function envArgs(env: Record<string, string>): string[] {
|
|
|
52
52
|
return Object.entries(env).flatMap(([k, v]) => ["-e", `${k}=${v}`]);
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
+
// Tool search is off on a routed provider, so every MCP server the user or
|
|
56
|
+
// the project has would put all its schemas in every prompt. A terminal
|
|
57
|
+
// agent reaches AgentOS through the aos CLI, so it needs none. Shell text
|
|
58
|
+
// for the agent's command line; empty on Claude.
|
|
59
|
+
export function routedMcpFlags(provider?: string | null): string {
|
|
60
|
+
return provider ? "--strict-mcp-config " : "";
|
|
61
|
+
}
|
|
62
|
+
|
|
55
63
|
// Written just before the agent's tmux session is created: a session with
|
|
56
64
|
// no prompt file is not one launchClaude started.
|
|
57
65
|
export const promptFileFor = (sessionId: string) =>
|
|
@@ -97,7 +105,8 @@ export async function launchClaude(opts: {
|
|
|
97
105
|
model: opts.model,
|
|
98
106
|
model_provider: opts.provider ?? null,
|
|
99
107
|
});
|
|
100
|
-
const
|
|
108
|
+
const mcpFlags = routedMcpFlags(opts.provider);
|
|
109
|
+
const agent = `export PATH=${shellQuote(AOS_BIN_DIR)}:"$HOME/.local/bin:$PATH"; ${routing.exportKey} ${provider.command} ${flags} ${mcpFlags}${CLAUDE_STATUS_SETTINGS_FLAG} --append-system-prompt-file ${shellQuote(briefFile)} "$(cat ${shellQuote(promptFile)})"; exec "\${SHELL:-/bin/sh}" -l`;
|
|
101
110
|
await execFileAsync(
|
|
102
111
|
"tmux",
|
|
103
112
|
[
|
package/lib/chat/driver.ts
CHANGED
|
@@ -30,6 +30,9 @@ export interface ChatStartOptions {
|
|
|
30
30
|
// Tools served in-process for this conversation, and tools it may use
|
|
31
31
|
// without asking.
|
|
32
32
|
mcpServers?: Record<string, McpServerConfig>;
|
|
33
|
+
// Load no MCP servers but those above: the user's own would otherwise
|
|
34
|
+
// put every tool schema in each prompt.
|
|
35
|
+
strictMcpConfig?: boolean;
|
|
33
36
|
allowedTools?: string[];
|
|
34
37
|
disallowedTools?: string[];
|
|
35
38
|
// A fixed permission mode in place of the access setting, which then
|
|
@@ -188,6 +188,7 @@ export const claudeDriver: ChatDriver = {
|
|
|
188
188
|
allowDangerouslySkipPermissions: true,
|
|
189
189
|
canUseTool: approvals.canUseTool,
|
|
190
190
|
mcpServers: options.mcpServers,
|
|
191
|
+
strictMcpConfig: options.strictMcpConfig,
|
|
191
192
|
allowedTools: options.allowedTools,
|
|
192
193
|
disallowedTools: options.disallowedTools,
|
|
193
194
|
hooks: {
|
package/lib/chat/refresh.ts
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import { db } from "../db";
|
|
14
|
+
import { effectiveModels } from "../models/config";
|
|
14
15
|
import { MAX_REFRESH_TOKENS, MIN_REFRESH_TOKENS } from "./refresh-limits";
|
|
15
16
|
|
|
16
17
|
export const ORCHESTRATOR_KEY = "orchestrator.refresh_tokens";
|
|
@@ -87,6 +88,25 @@ export function setRefreshSettings(input: Partial<RefreshSettings>): void {
|
|
|
87
88
|
// as 150 and clamps anything under 100k up to it).
|
|
88
89
|
export const AUTO_COMPACT_ENV = "CLAUDE_CODE_AUTO_COMPACT_WINDOW";
|
|
89
90
|
const AUTO_COMPACT_MIN = 100_000;
|
|
91
|
+
// Claude Code turns tool search off for a host that isn't Anthropic's, so
|
|
92
|
+
// every MCP and deferred tool schema rides in each prompt: measured on
|
|
93
|
+
// DeepSeek, the first call after a compaction is ~100k tokens against ~53k
|
|
94
|
+
// on Claude. A window measured from zero left it 15-30k of room, so it
|
|
95
|
+
// compacted every couple of minutes. Providers get that extra on top.
|
|
96
|
+
export const PROVIDER_BASE_TOKENS = 60_000;
|
|
97
|
+
|
|
98
|
+
// The compact threshold for a session on this provider (null: Anthropic).
|
|
99
|
+
export function compactThreshold(
|
|
100
|
+
tokens: number,
|
|
101
|
+
provider: string | null | undefined
|
|
102
|
+
): number {
|
|
103
|
+
if (tokens <= 0 || !provider) return tokens;
|
|
104
|
+
const window = effectiveModels().providers.find(
|
|
105
|
+
(p) => p.id === provider
|
|
106
|
+
)?.contextWindow;
|
|
107
|
+
const wanted = tokens + PROVIDER_BASE_TOKENS;
|
|
108
|
+
return window ? Math.min(wanted, window) : wanted;
|
|
109
|
+
}
|
|
90
110
|
|
|
91
111
|
// What an agent is launched with so it compacts itself at the threshold.
|
|
92
112
|
// Not an orchestrator: it starts over from its brief at its own threshold
|
|
@@ -95,11 +115,17 @@ const AUTO_COMPACT_MIN = 100_000;
|
|
|
95
115
|
// the user's own environment still applies.
|
|
96
116
|
export function autoCompactEnv(sessionId: string): Record<string, string> {
|
|
97
117
|
const row = db
|
|
98
|
-
.prepare(`SELECT role FROM sessions WHERE id = ?`)
|
|
99
|
-
.get(sessionId) as
|
|
118
|
+
.prepare(`SELECT role, model_provider FROM sessions WHERE id = ?`)
|
|
119
|
+
.get(sessionId) as
|
|
120
|
+
| { role: string | null; model_provider: string | null }
|
|
121
|
+
| undefined;
|
|
100
122
|
const tokens = refreshSettings().compactTokens;
|
|
101
123
|
if (row?.role === "orchestrator" || tokens <= 0) return {};
|
|
102
|
-
|
|
124
|
+
const window = compactThreshold(
|
|
125
|
+
Math.max(AUTO_COMPACT_MIN, tokens),
|
|
126
|
+
row?.model_provider
|
|
127
|
+
);
|
|
128
|
+
return { [AUTO_COMPACT_ENV]: String(window) };
|
|
103
129
|
}
|
|
104
130
|
|
|
105
131
|
const k = (tokens: number) => `${Math.round(tokens / 1000)}k`;
|
package/lib/chat/worker/host.ts
CHANGED
|
@@ -40,7 +40,7 @@ import {
|
|
|
40
40
|
visualsTools,
|
|
41
41
|
} from "../../artifacts/tools";
|
|
42
42
|
import type { RoleExtras } from "./extras";
|
|
43
|
-
import { refreshSettings, refreshedNote } from "../refresh";
|
|
43
|
+
import { compactThreshold, refreshSettings, refreshedNote } from "../refresh";
|
|
44
44
|
import { compactionDue, staleLabel, type Staleness } from "../stale";
|
|
45
45
|
import type { WorkerCommand, WorkerEvent } from "./protocol";
|
|
46
46
|
|
|
@@ -203,6 +203,10 @@ export class ChatHost {
|
|
|
203
203
|
mcpServers: visuals
|
|
204
204
|
? { ...extras.mcpServers, [VISUALS_SERVER]: visuals }
|
|
205
205
|
: extras.mcpServers,
|
|
206
|
+
// Claude Code turns tool search off on a non-Anthropic host, so each
|
|
207
|
+
// MCP server the user has adds all its schemas to every prompt
|
|
208
|
+
// (~45k tokens): a routed agent gets only the servers AgentOS gives it.
|
|
209
|
+
strictMcpConfig: !!session.model_provider,
|
|
206
210
|
allowedTools: extras.allowedTools,
|
|
207
211
|
disallowedTools: extras.disallowedTools,
|
|
208
212
|
permissionMode: extras.permissionMode,
|
|
@@ -743,7 +747,10 @@ export class ChatHost {
|
|
|
743
747
|
}
|
|
744
748
|
return compactionDue(context, {
|
|
745
749
|
state: this.state,
|
|
746
|
-
thresholdTokens:
|
|
750
|
+
thresholdTokens: compactThreshold(
|
|
751
|
+
refreshSettings().compactTokens,
|
|
752
|
+
this.session.model_provider
|
|
753
|
+
),
|
|
747
754
|
});
|
|
748
755
|
}
|
|
749
756
|
|
package/lib/models/config.ts
CHANGED
package/lib/models/providers.ts
CHANGED
|
@@ -37,6 +37,9 @@ export interface ModelProvider {
|
|
|
37
37
|
tiers?: ModelTiers;
|
|
38
38
|
// Plain settings the endpoint wants (a longer timeout, say). Never a key.
|
|
39
39
|
env?: Record<string, string>;
|
|
40
|
+
// The context window of its models, in tokens: Claude Code assumes a
|
|
41
|
+
// size from the model's name, and the compact window is capped at this.
|
|
42
|
+
contextWindow?: number;
|
|
40
43
|
enabled: boolean;
|
|
41
44
|
}
|
|
42
45
|
|
|
@@ -77,6 +80,9 @@ export const PROVIDER_PRESETS: ModelProvider[] = [
|
|
|
77
80
|
sonnet: "deepseek-flash",
|
|
78
81
|
haiku: "deepseek-flash",
|
|
79
82
|
},
|
|
83
|
+
// 1M for deepseek-flash (api-docs.deepseek.com/quick_start/pricing);
|
|
84
|
+
// deepseek-v4-pro's isn't stated there, and is assumed to match.
|
|
85
|
+
contextWindow: 1_000_000,
|
|
80
86
|
enabled: false,
|
|
81
87
|
},
|
|
82
88
|
{
|
|
@@ -88,6 +94,8 @@ export const PROVIDER_PRESETS: ModelProvider[] = [
|
|
|
88
94
|
models: ["glm-5.3", "glm-5.3-flash"],
|
|
89
95
|
tiers: { opus: "glm-5.3", sonnet: "glm-5.3", haiku: "glm-5.3-flash" },
|
|
90
96
|
env: { API_TIMEOUT_MS: "3000000" },
|
|
97
|
+
// docs.z.ai/guides/llm/glm-5.3
|
|
98
|
+
contextWindow: 1_000_000,
|
|
91
99
|
enabled: false,
|
|
92
100
|
},
|
|
93
101
|
];
|
package/lib/models/resolve.ts
CHANGED
|
@@ -218,6 +218,9 @@ function routingEnv(p: ModelProvider, model: string): Record<string, string> {
|
|
|
218
218
|
: "ANTHROPIC_API_KEY";
|
|
219
219
|
return {
|
|
220
220
|
...p.env,
|
|
221
|
+
...(p.contextWindow
|
|
222
|
+
? { CLAUDE_CODE_MAX_CONTEXT_TOKENS: String(p.contextWindow) }
|
|
223
|
+
: {}),
|
|
221
224
|
ANTHROPIC_BASE_URL: p.baseUrl!,
|
|
222
225
|
[other]: "",
|
|
223
226
|
ANTHROPIC_DEFAULT_OPUS_MODEL: p.tiers?.opus ?? model,
|
|
@@ -27,10 +27,15 @@ const modelRef = z
|
|
|
27
27
|
const modelOverride = z
|
|
28
28
|
.union([
|
|
29
29
|
modelRef,
|
|
30
|
-
z.partialRecord
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
// Named optional keys, not z.partialRecord: its "propertyNames" makes
|
|
31
|
+
// Claude Code drop every tool on this server, not just this one.
|
|
32
|
+
z
|
|
33
|
+
.object(
|
|
34
|
+
Object.fromEntries(
|
|
35
|
+
TASK_ROLES.map((role) => [role, modelRef.optional()])
|
|
36
|
+
) as Record<ModelRole, z.ZodOptional<typeof modelRef>>
|
|
37
|
+
)
|
|
38
|
+
.strict(),
|
|
34
39
|
])
|
|
35
40
|
.optional()
|
|
36
41
|
.describe(
|