titan-agent 5.0.2 → 5.0.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/dist/agent/agent.js +48 -3
- package/dist/agent/agent.js.map +1 -1
- package/dist/agent/agentLoop.js +83 -5
- package/dist/agent/agentLoop.js.map +1 -1
- package/dist/agent/commandPost.js +1 -1
- package/dist/agent/commandPost.js.map +1 -1
- package/dist/agent/goalProposer.js +2 -2
- package/dist/agent/goalProposer.js.map +1 -1
- package/dist/agent/missionDriver.js +1 -1
- package/dist/agent/missionDriver.js.map +1 -1
- package/dist/agent/promptBudget.js +85 -0
- package/dist/agent/promptBudget.js.map +1 -0
- package/dist/agent/structuredSpawn.js +1 -1
- package/dist/agent/structuredSpawn.js.map +1 -1
- package/dist/agent/subtaskTaxonomy.js +1 -1
- package/dist/agent/subtaskTaxonomy.js.map +1 -1
- package/dist/agent/systemPromptParts.js +10 -1
- package/dist/agent/systemPromptParts.js.map +1 -1
- package/dist/agent/toolRunner.js +16 -0
- package/dist/agent/toolRunner.js.map +1 -1
- package/dist/agent/toolSearch.js +4 -1
- package/dist/agent/toolSearch.js.map +1 -1
- package/dist/analytics/bugReports.js +1 -1
- package/dist/analytics/bugReports.js.map +1 -1
- package/dist/channels/messenger.js +1 -1
- package/dist/channels/messenger.js.map +1 -1
- package/dist/eval/harness.js +141 -0
- package/dist/eval/harness.js.map +1 -0
- package/dist/gateway/server.js +374 -74
- package/dist/gateway/server.js.map +1 -1
- package/dist/hooks/shellHooks.js +1 -1
- package/dist/hooks/shellHooks.js.map +1 -1
- package/dist/lib/auto-heal/repair-strategies.js.map +1 -1
- package/dist/memory/promptIncludes.js +58 -0
- package/dist/memory/promptIncludes.js.map +1 -0
- package/dist/organism/alertsStore.js +70 -0
- package/dist/organism/alertsStore.js.map +1 -0
- package/dist/plugins/memoryRetrieval.js.map +1 -1
- package/dist/providers/ollama.js +7 -7
- package/dist/providers/ollama.js.map +1 -1
- package/dist/safety/invariants.js +60 -0
- package/dist/safety/invariants.js.map +1 -0
- package/dist/safety/opusReview.js +1 -1
- package/dist/safety/opusReview.js.map +1 -1
- package/dist/security/commandScanner.js +2 -2
- package/dist/security/commandScanner.js.map +1 -1
- package/dist/security/secretGuard.js +4 -4
- package/dist/security/secretGuard.js.map +1 -1
- package/dist/skills/builtin/widget_gallery.js +28 -1
- package/dist/skills/builtin/widget_gallery.js.map +1 -1
- package/dist/skills/frontmatterLoader.js +119 -0
- package/dist/skills/frontmatterLoader.js.map +1 -0
- package/dist/skills/registry.js +20 -0
- package/dist/skills/registry.js.map +1 -1
- package/dist/testing/testHealthMonitor.js +1 -2
- package/dist/testing/testHealthMonitor.js.map +1 -1
- package/dist/utils/constants.js +2 -2
- package/dist/utils/constants.js.map +1 -1
- package/dist/utils/replyQuality.js +1 -1
- package/dist/utils/replyQuality.js.map +1 -1
- package/dist/utils/tokens.js +1 -1
- package/dist/utils/tokens.js.map +1 -1
- package/docs/bleeding-edge-agents-2026.md +450 -0
- package/docs/langchain-analysis.md +598 -0
- package/docs/langchain-code-analysis.md +363 -0
- package/docs/space-agent-analysis.md +300 -0
- package/package.json +1 -1
- package/ui/dist/assets/{AuditPanel-G7YA1HzV.js → AuditPanel-B84Mp16G.js} +2 -2
- package/ui/dist/assets/AutonomyPanel-DOtiTFxV.js +11 -0
- package/ui/dist/assets/{AutopilotPanel-CHRjxdh0.js → AutopilotPanel-nTb1Dnru.js} +1 -1
- package/ui/dist/assets/AutoresearchPanel-D46mX8VF.js +6 -0
- package/ui/dist/assets/BackupPanel-DGM1XXbG.js +1 -0
- package/ui/dist/assets/BrowserPanel-Cn1tTN3y.js +6 -0
- package/ui/dist/assets/{CPAgents-D5533PhK.js → CPAgents-CEraUkME.js} +1 -1
- package/ui/dist/assets/{CPDashboard-C-GgqDsI.js → CPDashboard-B_yidGAe.js} +2 -2
- package/ui/dist/assets/CPFiles-BBS8jtYH.js +1 -0
- package/ui/dist/assets/CPGoals-DL5v21TZ.js +1 -0
- package/ui/dist/assets/CPInbox-CyLQJBYF.js +11 -0
- package/ui/dist/assets/{CPSocial-mUQsrSh5.js → CPSocial-BkEtQ1Um.js} +3 -3
- package/ui/dist/assets/ChannelsPanel-CD2kHhA5.js +1 -0
- package/ui/dist/assets/CheckpointsPanel-BrUTFPu_.js +1 -0
- package/ui/dist/assets/CommandPostHub-BPPaUv1B.js +29 -0
- package/ui/dist/assets/CronPanel-CsfQctFp.js +1 -0
- package/ui/dist/assets/DaemonPanel-CNUggBbL.js +1 -0
- package/ui/dist/assets/DataTable-DuAEp_QJ.js +1 -0
- package/ui/dist/assets/{EmptyState-D60-wQrz.js → EmptyState-DFrAEZDm.js} +1 -1
- package/ui/dist/assets/EvalPanel-DEX0a5-b.js +1 -0
- package/ui/dist/assets/{FilesPanel-BNN3h_HW.js → FilesPanel-DATsiAqG.js} +1 -1
- package/ui/dist/assets/FleetPanel-QYQKqx4W.js +1 -0
- package/ui/dist/assets/{HomelabPanel-1mfhRBh6.js → HomelabPanel-DhuXd3ZD.js} +2 -2
- package/ui/dist/assets/{InfraView-Df6SFI7b.js → InfraView-eS7cpESw.js} +2 -2
- package/ui/dist/assets/InlineEditableField-zIAnW4AR.js +1 -0
- package/ui/dist/assets/{Input-DYukme8A.js → Input-bFsLI0fq.js} +1 -1
- package/ui/dist/assets/IntegrationsPanel-C_FswSRN.js +1 -0
- package/ui/dist/assets/IntelligenceView-smQ6aBwx.js +2 -0
- package/ui/dist/assets/{LearningPanel-BPx05bBu.js → LearningPanel-BEgF_iND.js} +1 -1
- package/ui/dist/assets/{LogsPanel-D3Qfp2SE.js → LogsPanel-Br1P8ST6.js} +1 -1
- package/ui/dist/assets/McpPanel-ByvQ12J_.js +1 -0
- package/ui/dist/assets/{MemoryGraphPanel-BFovwaSG.js → MemoryGraphPanel-BGOeSaET.js} +1 -1
- package/ui/dist/assets/MemoryWikiPanel-CR8btd66.js +11 -0
- package/ui/dist/assets/MeshPanel-BjkcSOMz.js +11 -0
- package/ui/dist/assets/NvidiaPanel-NYt42w7L.js +1 -0
- package/ui/dist/assets/OrganismPanel-PHvISvVn.js +1 -0
- package/ui/dist/assets/OverviewPanel-q35zdMr6.js +6 -0
- package/ui/dist/assets/{PageHeader-BdvxKoad.js → PageHeader-Cwn3OALc.js} +1 -1
- package/ui/dist/assets/PaperclipPanel-BDpQki0d.js +1 -0
- package/ui/dist/assets/{PersonasPanel-BpI6Npxv.js → PersonasPanel-DxrGW5C4.js} +1 -1
- package/ui/dist/assets/RecipesPanel-CYRdBx5u.js +1 -0
- package/ui/dist/assets/{SecurityPanel-CBDsEAFz.js → SecurityPanel-i1QMctV0.js} +1 -1
- package/ui/dist/assets/SelfImprovePanel-DbybAZWp.js +1 -0
- package/ui/dist/assets/SelfProposalsPanel-DtcTUDDd.js +2 -0
- package/ui/dist/assets/SessionsPanel-B7QmOizR.js +1 -0
- package/ui/dist/assets/SessionsTab-BdJj_vsI.js +1 -0
- package/ui/dist/assets/{SettingsPanel-BiWHsOAJ.js → SettingsPanel-DnEvJUFe.js} +1 -1
- package/ui/dist/assets/SettingsView-C39dk_yr.js +2 -0
- package/ui/dist/assets/{SkeletonLoader-CGtpZJ-7.js → SkeletonLoader-CsiR8ED9.js} +1 -1
- package/ui/dist/assets/{SkillsPanel-Z_9jA6dU.js → SkillsPanel-DM4qBFDS.js} +1 -1
- package/ui/dist/assets/{SomaView-AP3BXqf-.js → SomaView-CWnPKEQI.js} +1 -1
- package/ui/dist/assets/{StatCard-CrnvXPg5.js → StatCard-CY8lgeWm.js} +1 -1
- package/ui/dist/assets/{StatusBadge-B6r5EWBA.js → StatusBadge-CGvKbP7R.js} +1 -1
- package/ui/dist/assets/TeamsPanel-Bf6GaUni.js +1 -0
- package/ui/dist/assets/{TelemetryPanel-D6o14H-i.js → TelemetryPanel-JZ90gJXC.js} +1 -1
- package/ui/dist/assets/TitanCanvas-Hk49NFcA.js +1092 -0
- package/ui/dist/assets/ToolsView-Cq7Fuq3i.js +2 -0
- package/ui/dist/assets/{Tooltip-DNsYGHC9.js → Tooltip-CcoZrKsl.js} +1 -1
- package/ui/dist/assets/{TraceViewer-TOpdmqLF.js → TraceViewer-ojGf0drx.js} +1 -1
- package/ui/dist/assets/TrainingPanel-CWnP4H2l.js +1 -0
- package/ui/dist/assets/{VoiceOverlay-XIyCbAP7.js → VoiceOverlay-Dn6iaYgd.js} +1 -1
- package/ui/dist/assets/VramPanel-CLd9Ggck.js +1 -0
- package/ui/dist/assets/WatchView-CQBemwsm.js +13 -0
- package/ui/dist/assets/WorkTab-BOfTN-Bd.js +1 -0
- package/ui/dist/assets/WorkflowsPanel-qzNS0p0u.js +11 -0
- package/ui/dist/assets/{arrow-left-CQF-yBIU.js → arrow-left-c-8OFZUV.js} +1 -1
- package/ui/dist/assets/{chart-column-1smg0GbX.js → chart-column-x6L66Qw7.js} +1 -1
- package/ui/dist/assets/{circle-check-big-BiMDFx6C.js → circle-check-big-WaW3U3Xl.js} +1 -1
- package/ui/dist/assets/{dollar-sign-DMYH4Q_a.js → dollar-sign-D2Oce4Ru.js} +1 -1
- package/ui/dist/assets/{download-BYFd-yl6.js → download-YvPDLlFJ.js} +1 -1
- package/ui/dist/assets/eye-off-DIMcxsdQ.js +6 -0
- package/ui/dist/assets/{funnel-pWBglhfw.js → funnel-DqD9srZu.js} +1 -1
- package/ui/dist/assets/{git-branch-Cgqic2Us.js → git-branch-0FamUEbU.js} +1 -1
- package/ui/dist/assets/index-D932CbpQ.css +1 -0
- package/ui/dist/assets/index-NatBSFxj.js +227 -0
- package/ui/dist/assets/{legacy-BHbi-Nm_.js → legacy-DOO7F5cq.js} +1 -1
- package/ui/dist/assets/{lightbulb-D_y0Mtyq.js → lightbulb-Bk6KlR6q.js} +1 -1
- package/ui/dist/assets/pause-DDC_zUiJ.js +6 -0
- package/ui/dist/assets/{play-2xR4_zUG.js → play-BPXbHToG.js} +1 -1
- package/ui/dist/assets/{plug-DhvhYYy_.js → plug-Dxp-sWVF.js} +1 -1
- package/ui/dist/assets/proxy-vU7v4NVM.js +9 -0
- package/ui/dist/assets/square-Bn_0tYME.js +6 -0
- package/ui/dist/assets/target-BrtxUtzl.js +6 -0
- package/ui/dist/assets/toggle-right-CYphlpN5.js +11 -0
- package/ui/dist/assets/{trash-2-DmRaMz9e.js → trash-2-C_Jsp23A.js} +1 -1
- package/ui/dist/assets/{trending-up-DsDcs3Jo.js → trending-up-DrtLViSm.js} +1 -1
- package/ui/dist/assets/trophy-DdRzAOfo.js +6 -0
- package/ui/dist/index.html +2 -2
- package/ui/dist/assets/CPFiles-G7veSjMg.js +0 -6
- package/ui/dist/assets/CPGoals-C3DlKJrJ.js +0 -1
- package/ui/dist/assets/CPInbox-D10curQs.js +0 -16
- package/ui/dist/assets/ChannelsPanel-M3pO2htW.js +0 -1
- package/ui/dist/assets/CommandPostHub-CW9OY1A4.js +0 -37
- package/ui/dist/assets/InlineEditableField-CH-jR3LC.js +0 -11
- package/ui/dist/assets/IntegrationsPanel-EaN999Te.js +0 -1
- package/ui/dist/assets/IntelligenceView-Q4DBmJpJ.js +0 -2
- package/ui/dist/assets/McpPanel-zC7jTaSx.js +0 -6
- package/ui/dist/assets/MeshPanel-CqtYZ74K.js +0 -11
- package/ui/dist/assets/NvidiaPanel-BVIZFHet.js +0 -1
- package/ui/dist/assets/SelfImprovePanel-PSCYO6sx.js +0 -11
- package/ui/dist/assets/SessionsTab-Cn3dGgjX.js +0 -1
- package/ui/dist/assets/SettingsView-3BSIzAfW.js +0 -2
- package/ui/dist/assets/TitanCanvas-cnb7R1gS.js +0 -1056
- package/ui/dist/assets/ToolsView-Dp-xUWJG.js +0 -2
- package/ui/dist/assets/WorkTab-Pgq-iLz9.js +0 -1
- package/ui/dist/assets/WorkflowsPanel-B91LeW7r.js +0 -21
- package/ui/dist/assets/eye-BfW7UcEC.js +0 -11
- package/ui/dist/assets/index-BWSnB6Kr.js +0 -227
- package/ui/dist/assets/index-Dtw1pbjc.css +0 -1
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
# LangChain.js Code-Level Analysis for TITAN
|
|
2
|
+
|
|
3
|
+
> **Date:** 2026-04-25
|
|
4
|
+
> **Source:** `langchainjs` monorepo (shallow clone at `/tmp/langchainjs-analysis`)
|
|
5
|
+
> **Focus:** Specific code patterns, file paths, and implementation details TITAN could adopt.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Executive Summary
|
|
10
|
+
|
|
11
|
+
LangChain.js (`libs/langchain-core/`, `libs/langchain/`, `libs/langchain-mcp-adapters/`) is a **TypeScript-first agent framework** with three layers:
|
|
12
|
+
|
|
13
|
+
| Layer | Package | Key Files |
|
|
14
|
+
|-------|---------|-----------|
|
|
15
|
+
| **Core** | `@langchain/core` | `tools/index.ts`, `messages/tool.ts`, `callbacks/manager.ts` |
|
|
16
|
+
| **Agents** | `langchain` | `agents/middleware/*.ts`, `agents/state.ts` |
|
|
17
|
+
| **MCP** | `@langchain/mcp-adapters` | `tools.ts`, `client.ts`, `connection.ts` |
|
|
18
|
+
|
|
19
|
+
For TITAN, the highest-value borrowable patterns are:
|
|
20
|
+
1. **Tool schema bridge** — JSON Schema ↔ Zod conversion for MCP tools
|
|
21
|
+
2. **Agent middleware** — Model call limits, PII redaction, context editing
|
|
22
|
+
3. **Callback manager** — Hierarchical tracing for tool calls and agent steps
|
|
23
|
+
4. **DynamicStructuredTool** — Runtime tool creation from schemas
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## 1. Tool System Deep Dive
|
|
28
|
+
|
|
29
|
+
### 1.1 StructuredTool Base Class
|
|
30
|
+
**File:** `libs/langchain-core/src/tools/index.ts` (lines 100–300)
|
|
31
|
+
|
|
32
|
+
LangChain's tool hierarchy:
|
|
33
|
+
```
|
|
34
|
+
BaseLangChain
|
|
35
|
+
└── StructuredTool<SchemaT, OutputT>
|
|
36
|
+
├── name: string
|
|
37
|
+
├── description: string
|
|
38
|
+
├── schema: SchemaT (Zod or JSON Schema)
|
|
39
|
+
├── _call(args, runManager, config) → Promise<OutputT>
|
|
40
|
+
└── invoke(input, config) → Promise<ToolMessage>
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Key design decisions:
|
|
44
|
+
- **Schema-driven**: Every tool has a typed schema. The LLM receives the schema as function-calling metadata.
|
|
45
|
+
- **Run manager injection**: `_call` receives a `CallbackManagerForToolRun` so tools can emit events, log errors, and report progress.
|
|
46
|
+
- **Tool messages**: Output is wrapped in `ToolMessage` with `tool_call_id` linkage to the originating `ToolCall`.
|
|
47
|
+
|
|
48
|
+
**TITAN adaptation:**
|
|
49
|
+
TITAN's tools are plain functions. Adopting a `StructuredTool` base would:
|
|
50
|
+
- Standardize schema definitions (currently ad-hoc Zod in each tool file)
|
|
51
|
+
- Enable callback tracing for every tool invocation
|
|
52
|
+
- Make tool output format consistent for the LLM
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
// TITAN-style adaptation
|
|
56
|
+
abstract class TitanTool<
|
|
57
|
+
Schema extends z.ZodTypeAny,
|
|
58
|
+
Output = unknown
|
|
59
|
+
> {
|
|
60
|
+
abstract name: string;
|
|
61
|
+
abstract description: string;
|
|
62
|
+
abstract schema: Schema;
|
|
63
|
+
|
|
64
|
+
async invoke(args: z.infer<Schema>, ctx: ToolContext): Promise<ToolResult> {
|
|
65
|
+
const validated = this.schema.parse(args);
|
|
66
|
+
const result = await this._call(validated, ctx);
|
|
67
|
+
return { toolCallId: ctx.toolCallId, content: JSON.stringify(result) };
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
protected abstract _call(args: z.infer<Schema>, ctx: ToolContext): Promise<Output>;
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### 1.2 DynamicStructuredTool — Runtime Tool Creation
|
|
75
|
+
**File:** `libs/langchain-core/src/tools/index.ts` (lines 900–1000)
|
|
76
|
+
|
|
77
|
+
`DynamicStructuredTool` lets you create a tool at runtime from a name, description, schema, and function:
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
const tool = new DynamicStructuredTool({
|
|
81
|
+
name: "weather",
|
|
82
|
+
description: "Get weather for a city",
|
|
83
|
+
schema: z.object({ city: z.string() }),
|
|
84
|
+
func: async (args) => {
|
|
85
|
+
return await fetchWeather(args.city);
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
**TITAN adaptation:**
|
|
91
|
+
TITAN already has dynamic tool loading via MCP. But `DynamicStructuredTool` would enable:
|
|
92
|
+
- User-defined tools via the UI (name + description + schema + code)
|
|
93
|
+
- Agent-generated tools (the agent writes a function, TITAN wraps it)
|
|
94
|
+
- Hot-reloading of tools without restarting the gateway
|
|
95
|
+
|
|
96
|
+
### 1.3 MCP Tool Adapter — JSON Schema Bridge
|
|
97
|
+
**File:** `libs/langchain-mcp-adapters/src/tools.ts` (lines 1192–1300)
|
|
98
|
+
|
|
99
|
+
This is the **most relevant file** for TITAN. It shows how LangChain converts MCP tools to LangChain tools:
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
export async function loadMcpTools(
|
|
103
|
+
serverName: string,
|
|
104
|
+
client: MCPInstance,
|
|
105
|
+
options?: LoadMcpToolsOptions
|
|
106
|
+
): Promise<DynamicStructuredTool[]> {
|
|
107
|
+
const mcpTools = await client.listTools();
|
|
108
|
+
|
|
109
|
+
return mcpTools.map(tool => {
|
|
110
|
+
// 1. Dereference $defs/$ref in JSON Schema
|
|
111
|
+
const dereferenced = dereferenceJsonSchema(tool.inputSchema);
|
|
112
|
+
|
|
113
|
+
// 2. Simplify schema for LLM compatibility
|
|
114
|
+
// (remove allOf, anyOf, oneOf, if/then/else, not)
|
|
115
|
+
const simplified = simplifyJsonSchemaForLLM(dereferenced);
|
|
116
|
+
|
|
117
|
+
// 3. Wrap as DynamicStructuredTool
|
|
118
|
+
return new DynamicStructuredTool({
|
|
119
|
+
name: `${serverName}__${tool.name}`,
|
|
120
|
+
description: tool.description,
|
|
121
|
+
schema: simplified, // JSON Schema (not Zod!)
|
|
122
|
+
func: async (args) => {
|
|
123
|
+
return await client.callTool({ name: tool.name, arguments: args });
|
|
124
|
+
},
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
**Critical patterns:**
|
|
131
|
+
- **Schema dereferencing**: Resolves `$ref` pointers to `$defs` definitions. Pydantic v2 emits schemas with `$defs`; without dereferencing, OpenAI rejects them.
|
|
132
|
+
- **Schema simplification**: Removes `allOf`, `anyOf`, `oneOf`, `if/then/else`, `not` — patterns that OpenAI's function-calling API doesn't support.
|
|
133
|
+
- **Tool namespacing**: Prefixes tool names with server name (`serverName__toolName`) to avoid collisions across MCP servers.
|
|
134
|
+
|
|
135
|
+
**TITAN adaptation:**
|
|
136
|
+
TITAN's MCP integration in `src/mcp/` likely has similar logic but may lack the schema simplification step. Adding `dereferenceJsonSchema` and `simplifyJsonSchemaForLLM` would fix MCP tool failures with Pydantic v2 servers.
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
// TITAN: src/mcp/client.ts enhancement
|
|
140
|
+
import { dereferenceJsonSchema, simplifyJsonSchemaForLLM } from './schemaUtils';
|
|
141
|
+
|
|
142
|
+
async function loadMcpTools(client: MCPClient): Promise<TitanTool[]> {
|
|
143
|
+
const { tools } = await client.listTools();
|
|
144
|
+
return tools.map(mcpTool => {
|
|
145
|
+
const schema = simplifyJsonSchemaForLLM(
|
|
146
|
+
dereferenceJsonSchema(mcpTool.inputSchema)
|
|
147
|
+
);
|
|
148
|
+
return {
|
|
149
|
+
name: mcpTool.name,
|
|
150
|
+
description: mcpTool.description,
|
|
151
|
+
schema,
|
|
152
|
+
handler: (args) => client.callTool(mcpTool.name, args),
|
|
153
|
+
};
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## 2. Agent Middleware Pattern
|
|
161
|
+
|
|
162
|
+
**Files:** `libs/langchain/src/agents/middleware/*.ts`
|
|
163
|
+
|
|
164
|
+
LangChain agents use a **middleware pipeline** — composable wrappers around the core agent loop:
|
|
165
|
+
|
|
166
|
+
| Middleware | File | Purpose |
|
|
167
|
+
|------------|------|---------|
|
|
168
|
+
| `modelCallLimit` | `middleware/modelCallLimit.ts` | Caps model calls per thread/run |
|
|
169
|
+
| `piiRedaction` | `middleware/piiRedaction.ts` | Detects/redacts PII in messages |
|
|
170
|
+
| `contextEditing` | `middleware/contextEditing.ts` | Summarizes/trims context when too long |
|
|
171
|
+
| `toolEmulator` | `middleware/toolEmulator.ts` | Simulates tool calls for testing |
|
|
172
|
+
|
|
173
|
+
### 2.1 Model Call Limit Middleware
|
|
174
|
+
**File:** `libs/langchain/src/agents/middleware/modelCallLimit.ts`
|
|
175
|
+
|
|
176
|
+
```typescript
|
|
177
|
+
const contextSchema = z.object({
|
|
178
|
+
threadLimit: z.number().optional(),
|
|
179
|
+
runLimit: z.number().optional(),
|
|
180
|
+
exitBehavior: z.enum(["error", "end"]).optional(),
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
const stateSchema = z.object({
|
|
184
|
+
threadModelCallCount: z.number().default(0),
|
|
185
|
+
runModelCallCount: z.number().default(0),
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
export const modelCallLimitMiddleware = createMiddleware({
|
|
189
|
+
contextSchema,
|
|
190
|
+
stateSchema,
|
|
191
|
+
onModelCall: (state, context) => {
|
|
192
|
+
state.runModelCallCount++;
|
|
193
|
+
state.threadModelCallCount++;
|
|
194
|
+
if (context.runLimit && state.runModelCallCount > context.runLimit) {
|
|
195
|
+
throw new ModelCallLimitMiddlewareError({ ... });
|
|
196
|
+
}
|
|
197
|
+
},
|
|
198
|
+
});
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
**TITAN adaptation:**
|
|
202
|
+
TITAN has a `maxRounds` limit but no per-thread or per-run call tracking. Adopting middleware would:
|
|
203
|
+
- Enable budget-based agent control (e.g., "use max 5 model calls for this task")
|
|
204
|
+
- Track token and call usage across agent runs for cost accounting
|
|
205
|
+
- Support graceful degradation instead of hard errors
|
|
206
|
+
|
|
207
|
+
### 2.2 PII Redaction Middleware
|
|
208
|
+
**File:** `libs/langchain/src/agents/middleware/piiRedaction.ts`
|
|
209
|
+
|
|
210
|
+
Scans all messages for regex patterns (email, SSN, phone, etc.), replaces matches with `[REDACTED_ID]`, and stores originals in a redaction map. Tool outputs are automatically restored before display.
|
|
211
|
+
|
|
212
|
+
**TITAN adaptation:**
|
|
213
|
+
TITAN's guardrails check for violations but don't redact PII. Adding redaction middleware would:
|
|
214
|
+
- Prevent sensitive data from reaching LLM providers
|
|
215
|
+
- Store redaction map in the session for audit trails
|
|
216
|
+
- Restore original values in tool outputs for local display
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## 3. Callback Manager — Observability
|
|
221
|
+
|
|
222
|
+
**File:** `libs/langchain-core/src/callbacks/manager.ts`
|
|
223
|
+
|
|
224
|
+
LangChain's callback system is hierarchical:
|
|
225
|
+
|
|
226
|
+
```
|
|
227
|
+
CallbackManager (agent-level)
|
|
228
|
+
├── CallbackManagerForLLMRun (each LLM call)
|
|
229
|
+
├── CallbackManagerForToolRun (each tool call)
|
|
230
|
+
│ ├── onToolStart(tool, input)
|
|
231
|
+
│ ├── onToolEnd(output)
|
|
232
|
+
│ └── onToolError(error)
|
|
233
|
+
└── CallbackManagerForChainRun (each chain step)
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
Every `invoke()` call receives a config with callbacks. This enables:
|
|
237
|
+
- **Tracing**: LangSmith listens to callbacks and builds trace trees
|
|
238
|
+
- **Logging**: Custom loggers emit structured events
|
|
239
|
+
- **Progress**: UI progress bars update via `onToolStart`/`onToolEnd`
|
|
240
|
+
|
|
241
|
+
**TITAN adaptation:**
|
|
242
|
+
TITAN's agent loop emits events but lacks a structured callback hierarchy. Adopting callbacks would:
|
|
243
|
+
- Replace ad-hoc `logger.info(COMPONENT, ...)` with typed events
|
|
244
|
+
- Enable LangSmith integration for external observability
|
|
245
|
+
- Support real-time UI updates (progress bars, tool call visualization)
|
|
246
|
+
|
|
247
|
+
```typescript
|
|
248
|
+
// TITAN-style callback hierarchy
|
|
249
|
+
interface TitanCallbackHandler {
|
|
250
|
+
onAgentStart?(sessionId: string, goal: string): void;
|
|
251
|
+
onToolStart?(toolCallId: string, toolName: string, args: unknown): void;
|
|
252
|
+
onToolEnd?(toolCallId: string, result: unknown, durationMs: number): void;
|
|
253
|
+
onToolError?(toolCallId: string, error: Error): void;
|
|
254
|
+
onAgentEnd?(sessionId: string, summary: string): void;
|
|
255
|
+
}
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
## 4. Message Types — ToolCall / ToolMessage Linkage
|
|
261
|
+
|
|
262
|
+
**File:** `libs/langchain-core/src/messages/tool.ts`
|
|
263
|
+
|
|
264
|
+
LangChain uses explicit `ToolCall` and `ToolMessage` types with `tool_call_id` linkage:
|
|
265
|
+
|
|
266
|
+
```typescript
|
|
267
|
+
interface ToolCall {
|
|
268
|
+
id: string; // e.g. "call_abc123"
|
|
269
|
+
name: string; // tool name
|
|
270
|
+
args: Record<string, unknown>;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
class ToolMessage extends BaseMessage {
|
|
274
|
+
tool_call_id: string; // links back to ToolCall
|
|
275
|
+
name?: string; // tool name (for tracing)
|
|
276
|
+
artifact?: unknown; // structured data for programmatic use
|
|
277
|
+
}
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
The `artifact` field is especially useful: it holds structured data (JSON, objects) while `content` holds the human-readable string.
|
|
281
|
+
|
|
282
|
+
**TITAN adaptation:**
|
|
283
|
+
TITAN's tool results are plain strings or raw objects. Adopting `ToolMessage` would:
|
|
284
|
+
- Enable reliable tool call → result linkage (currently inferred by order)
|
|
285
|
+
- Support artifacts for widget creation (the `_____react` payload could be an artifact)
|
|
286
|
+
- Make trace trees accurate for debugging
|
|
287
|
+
|
|
288
|
+
---
|
|
289
|
+
|
|
290
|
+
## 5. Runnable Interface — Composable Pipelines
|
|
291
|
+
|
|
292
|
+
**File:** `libs/langchain-core/src/runnables/base.ts`
|
|
293
|
+
|
|
294
|
+
LangChain's `Runnable` interface is the backbone of composition:
|
|
295
|
+
|
|
296
|
+
```typescript
|
|
297
|
+
interface Runnable<Input, Output> {
|
|
298
|
+
invoke(input: Input, config?: RunnableConfig): Promise<Output>;
|
|
299
|
+
stream(input: Input, config?: RunnableConfig): AsyncGenerator<Output>;
|
|
300
|
+
batch(inputs: Input[], config?: RunnableConfig): Promise<Output[]>;
|
|
301
|
+
pipe(other: Runnable<Output, Next>): Runnable<Input, Next>;
|
|
302
|
+
}
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
Every component (LLM, tool, chain, agent) implements `Runnable`. This enables:
|
|
306
|
+
- **Piping**: `llm.pipe(parser).pipe(tool)` composes operations
|
|
307
|
+
- **Streaming**: Every component supports streaming out of the box
|
|
308
|
+
- **Batching**: Run multiple inputs in parallel
|
|
309
|
+
- **Config passing**: `RunnableConfig` carries callbacks, metadata, and tags through the pipeline
|
|
310
|
+
|
|
311
|
+
**TITAN adaptation:**
|
|
312
|
+
TITAN's agent loop is a hand-coded state machine. Adopting `Runnable` would:
|
|
313
|
+
- Enable composable agent pipelines (e.g., `router.pipe(agent).pipe(reviewer)`)
|
|
314
|
+
- Support streaming tool results to the UI without polling
|
|
315
|
+
- Make testing easier (mock any Runnable in the pipeline)
|
|
316
|
+
|
|
317
|
+
---
|
|
318
|
+
|
|
319
|
+
## Integration Roadmap
|
|
320
|
+
|
|
321
|
+
### Phase 1: Schema Utilities (Week 1)
|
|
322
|
+
- Copy `dereferenceJsonSchema` and `simplifyJsonSchemaForLLM` from `libs/langchain-mcp-adapters/src/tools.ts`
|
|
323
|
+
- Add to `src/mcp/schemaUtils.ts`
|
|
324
|
+
- Fix Pydantic v2 MCP tool loading
|
|
325
|
+
|
|
326
|
+
### Phase 2: Tool Base Class (Week 2)
|
|
327
|
+
- Create `src/lib/TitanTool.ts` with `StructuredTool`-like interface
|
|
328
|
+
- Migrate 5 most-used tools (shell, read_file, web_search, memory, system_info)
|
|
329
|
+
- Add callback manager injection
|
|
330
|
+
|
|
331
|
+
### Phase 3: Middleware (Week 3)
|
|
332
|
+
- Implement `modelCallLimit` middleware for agent loop
|
|
333
|
+
- Implement `piiRedaction` middleware for safety
|
|
334
|
+
- Add middleware pipeline to `agentLoop.ts`
|
|
335
|
+
|
|
336
|
+
### Phase 4: Callback System (Week 4)
|
|
337
|
+
- Create `TitanCallbackManager` with `onToolStart`/`onToolEnd`/`onToolError`
|
|
338
|
+
- Integrate with existing event stream (`/api/sessions/:id/events`)
|
|
339
|
+
- Add LangSmith exporter option
|
|
340
|
+
|
|
341
|
+
### Phase 5: Runnable Refactor (Month 2)
|
|
342
|
+
- Refactor agent loop as `Runnable` pipeline
|
|
343
|
+
- Enable streaming responses without SSE polling
|
|
344
|
+
- Support batch tool execution
|
|
345
|
+
|
|
346
|
+
---
|
|
347
|
+
|
|
348
|
+
## Files Referenced
|
|
349
|
+
|
|
350
|
+
| File | Lines | Role |
|
|
351
|
+
|------|-------|------|
|
|
352
|
+
| `libs/langchain-core/src/tools/index.ts` | ~1000 | StructuredTool, DynamicStructuredTool base classes |
|
|
353
|
+
| `libs/langchain-core/src/tools/types.ts` | ~200 | Tool interface definitions |
|
|
354
|
+
| `libs/langchain-core/src/messages/tool.ts` | ~150 | ToolCall, ToolMessage types |
|
|
355
|
+
| `libs/langchain-core/src/callbacks/manager.ts` | ~800 | CallbackManager hierarchy |
|
|
356
|
+
| `libs/langchain-core/src/runnables/base.ts` | ~1500 | Runnable interface, piping, streaming |
|
|
357
|
+
| `libs/langchain-mcp-adapters/src/tools.ts` | ~1300 | MCP tool loading, schema dereference/simplify |
|
|
358
|
+
| `libs/langchain-mcp-adapters/src/client.ts` | ~200 | MCP client wrapper |
|
|
359
|
+
| `libs/langchain/src/agents/middleware/modelCallLimit.ts` | ~100 | Model call budget enforcement |
|
|
360
|
+
| `libs/langchain/src/agents/middleware/piiRedaction.ts` | ~150 | PII detection and redaction |
|
|
361
|
+
| `libs/langchain/src/agents/middleware/contextEditing.ts` | ~100 | Context summarization |
|
|
362
|
+
| `libs/langchain/src/agents/middleware/toolEmulator.ts` | ~80 | Tool call simulation for testing |
|
|
363
|
+
| `libs/langchain/src/agents/middleware.ts` | ~200 | Middleware creation helpers |
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
# Space-Agent Analysis for TITAN
|
|
2
|
+
|
|
3
|
+
> **Date:** 2026-04-25
|
|
4
|
+
> **Source:** https://github.com/agent0ai/space-agent (shallow clone at `/tmp/space-agent-analysis`)
|
|
5
|
+
> **Goal:** Identify specific code patterns, features, and architectural decisions TITAN could borrow or adapt.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Executive Summary
|
|
10
|
+
|
|
11
|
+
Space-agent is a **browser-first, server-last** AI agent platform. Unlike TITAN's Node.js-centric architecture, space-agent runs the agent loop, tool execution, and state management **entirely in the browser** using Alpine.js. The Node backend is thin — just CORS proxying, auth, and file serving.
|
|
12
|
+
|
|
13
|
+
This is a radically different architecture, but several patterns are highly borrowable:
|
|
14
|
+
|
|
15
|
+
1. **Prompt-budget enforcement** — ratio-based token caps with cached counts
|
|
16
|
+
2. **Skill frontmatter system** — Markdown + YAML auto-discovery with context tags
|
|
17
|
+
3. **Widget-as-function-source** — widgets store their renderer as JS source, not React components
|
|
18
|
+
4. **Deterministic LLM eval harness** — JSON test cases with A/B/C prompt triads
|
|
19
|
+
5. **Layered customware** — `L0` firmware → `L1` group → `L2` user inheritance
|
|
20
|
+
6. **Prompt-include memory** — `*.system.include.md` files as agent-editable memory
|
|
21
|
+
|
|
22
|
+
**Bottom line:** TITAN should adopt the **skill frontmatter**, **prompt-budget**, and **eval harness** patterns. The browser-first architecture is incompatible with TITAN's Node.js backend, but the execution protocol (`_____javascript` gate + Proxy sandbox) could inspire a client-side tool runner.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Architecture Comparison
|
|
27
|
+
|
|
28
|
+
| Dimension | Space-Agent | TITAN | Verdict |
|
|
29
|
+
|-----------|-------------|-------|---------|
|
|
30
|
+
| **Runtime** | Browser (Alpine.js) | Node.js + React UI | Different — not directly comparable |
|
|
31
|
+
| **Agent Loop** | Frontend `onscreen_agent/execution.js` | Backend `src/agent/agentLoop.ts` | Space-agent avoids server round-trips; TITAN has richer orchestration |
|
|
32
|
+
| **State** | Alpine stores (`init`/`mount`/`unmount`) | React hooks + Zustand + CRDT | TITAN's CRDT spatial state is more sophisticated |
|
|
33
|
+
| **Tools** | `_____javascript` gate + browser eval | Backend function calls | Space-agent's sandboxed eval is interesting for client-side tools |
|
|
34
|
+
| **Skills** | Markdown + YAML frontmatter | TypeScript registry + JSON config | **TITAN should adopt frontmatter skills** |
|
|
35
|
+
| **Memory** | Prompt-include files (`*.include.md`) | Vector + graph + JSON | **TITAN should adopt prompt-includes for user memory** |
|
|
36
|
+
| **UI Canvas** | Signed-grid camera panning + widget-as-code | React GridLayout + system components | Different philosophies; widget-as-code enables user-generated widgets |
|
|
37
|
+
| **Testing** | JSON case harness + A/B/C triads | Test health monitor + canary eval | **TITAN should adopt deterministic JSON eval cases** |
|
|
38
|
+
| **Deployment** | Electron + `node space supervise` | systemd + rsync | Space-agent's zero-downtime supervisor is worth studying |
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Feature-by-Feature Deep Dive
|
|
43
|
+
|
|
44
|
+
### 1. Agent Execution Protocol
|
|
45
|
+
**Primary File:** `app/L0/_all/mod/_core/onscreen_agent/execution.js`
|
|
46
|
+
|
|
47
|
+
Space-agent's execution loop uses a **gated protocol** similar to TITAN's `_____react` gate:
|
|
48
|
+
|
|
49
|
+
- `_____user` — human message block
|
|
50
|
+
- `_____framework` — runtime telemetry (token counts, budgets)
|
|
51
|
+
- `_____transient` — mutable context that gets trimmed first
|
|
52
|
+
- `_____javascript` — code execution gate (like TITAN's tool calls)
|
|
53
|
+
|
|
54
|
+
The JavaScript gate runs in a **Proxy-scoped sandbox** using `with (proxyScope) { eval(code) }`. This allows the agent to execute arbitrary code safely without a backend round-trip.
|
|
55
|
+
|
|
56
|
+
**Borrowable for TITAN:**
|
|
57
|
+
- Adopt the `_____user` / `_____framework` / `_____transient` block markers in the system prompt for cleaner context separation.
|
|
58
|
+
- Consider a client-side JavaScript tool for rapid UI manipulation (like `document.querySelector` tweaks) without backend latency.
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
### 2. Skill System
|
|
63
|
+
**Primary File:** `app/L0/_all/mod/_core/skillset/skills.js`
|
|
64
|
+
|
|
65
|
+
Skills are **Markdown files with YAML frontmatter**:
|
|
66
|
+
|
|
67
|
+
```markdown
|
|
68
|
+
---
|
|
69
|
+
name: web_search
|
|
70
|
+
description: Search the web
|
|
71
|
+
context_tags: [web, research]
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
When the user asks about current events, use this skill to search...
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
The system:
|
|
78
|
+
1. Discovers all `SKILL.md` files recursively
|
|
79
|
+
2. Parses frontmatter for metadata
|
|
80
|
+
3. Auto-loads skills whose `context_tags` match the current conversation context
|
|
81
|
+
4. Detects conflicts (two skills claiming the same trigger)
|
|
82
|
+
|
|
83
|
+
**Borrowable for TITAN:**
|
|
84
|
+
- **High priority.** TITAN's skills are TypeScript modules in `src/skills/`. Adding a Markdown frontmatter layer would let users define skills without writing code.
|
|
85
|
+
- The `context_tags` auto-loading mechanism could replace TITAN's manual skill registration.
|
|
86
|
+
- Conflict detection would improve TITAN's skill reliability.
|
|
87
|
+
|
|
88
|
+
**Implementation sketch:**
|
|
89
|
+
```typescript
|
|
90
|
+
// src/skills/frontmatterLoader.ts
|
|
91
|
+
import matter from 'gray-matter';
|
|
92
|
+
|
|
93
|
+
export function loadFrontmatterSkills(dir: string): Skill[] {
|
|
94
|
+
const files = globSync(`${dir}/**/SKILL.md`);
|
|
95
|
+
return files.map(path => {
|
|
96
|
+
const { data, content } = matter(readFileSync(path, 'utf-8'));
|
|
97
|
+
return {
|
|
98
|
+
name: data.name,
|
|
99
|
+
tags: data.context_tags || [],
|
|
100
|
+
prompt: content,
|
|
101
|
+
source: path,
|
|
102
|
+
};
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
### 3. Widget Canvas & UI
|
|
110
|
+
**Primary Files:** `app/L0/_all/mod/_core/spaces/store.js`, `layout.js`
|
|
111
|
+
|
|
112
|
+
Space-agent's canvas uses a **signed integer grid** (camera panning) rather than CSS GridLayout. Widgets are stored as **YAML with embedded JavaScript source**:
|
|
113
|
+
|
|
114
|
+
```yaml
|
|
115
|
+
widgets:
|
|
116
|
+
- id: todo-list
|
|
117
|
+
x: 0
|
|
118
|
+
y: 0
|
|
119
|
+
w: 4
|
|
120
|
+
h: 3
|
|
121
|
+
source: |
|
|
122
|
+
function render() {
|
|
123
|
+
return `<ul>${items.map(i => `<li>${i}</li>`).join('')}</ul>`;
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
The widget renderer is a **function string that gets `new Function()`'d** at runtime. This means users (and agents) can create entirely new widget types on the fly without redeploying the app.
|
|
128
|
+
|
|
129
|
+
**Borrowable for TITAN:**
|
|
130
|
+
- **Medium priority.** TITAN's React component registry is more robust but requires a rebuild for new widgets.
|
|
131
|
+
- A hybrid approach: keep system widgets as React components, but add a **"code widget"** type that accepts a JS function string and renders it in an iframe sandbox.
|
|
132
|
+
- This would enable the agent to generate truly novel widgets (charts, custom layouts, interactive forms) without pre-built components.
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
### 4. Memory & Prompt Context
|
|
137
|
+
**Primary Files:** `app/L0/_all/mod/_core/memory/`, `promptinclude/promptinclude.js`
|
|
138
|
+
|
|
139
|
+
Space-agent's memory system is elegantly simple:
|
|
140
|
+
|
|
141
|
+
1. **Prompt-include files** — `*.system.include.md`, `*.transient.include.md` in the project directory
|
|
142
|
+
2. **Auto-discovery** — The prompt builder scans for these files and includes them in the appropriate budget section
|
|
143
|
+
3. **Agent-editable** — The agent can write to these files to persist memory across sessions
|
|
144
|
+
4. **Source-attributed** — Each include block is fenced with its file path so the LLM knows where the context came from
|
|
145
|
+
|
|
146
|
+
**Borrowable for TITAN:**
|
|
147
|
+
- **High priority.** TITAN has vector/graph memory but lacks a simple file-based prompt inclusion system.
|
|
148
|
+
- Adding `~/.titan/includes/*.system.include.md` would let users (and agents) maintain long-lived context without database complexity.
|
|
149
|
+
- The agent could edit these files directly via the `write_file` tool, making memory updates transparent and version-controlled.
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
### 5. Testing & Evaluation
|
|
154
|
+
**Primary File:** `tests/agent_llm_performance/test.mjs`
|
|
155
|
+
|
|
156
|
+
Space-agent has a **deterministic LLM evaluation harness**:
|
|
157
|
+
|
|
158
|
+
1. **JSON test cases** — Each case has `input`, `expected_behavior`, and `assertions`
|
|
159
|
+
2. **A/B/C prompt triads** — Tests run against multiple prompt variants to measure robustness
|
|
160
|
+
3. **Living leaderboard** — Results are stored in `results/` with timestamps; a leaderboard tracks which prompt version performs best
|
|
161
|
+
4. **Pass/fail JSON** — The LLM outputs a JSON object with `passed: boolean` and `reason` fields
|
|
162
|
+
|
|
163
|
+
**Borrowable for TITAN:**
|
|
164
|
+
- **High priority.** TITAN has `testHealthMonitor.ts` but lacks structured LLM eval cases.
|
|
165
|
+
- Adding a JSON case format for agent behavior would enable regression testing of the widget creation pipeline.
|
|
166
|
+
- Example: "Given input 'show me my backups', assert that agent calls `backup_list` then `gallery_search` for `system:backup`."
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
### 6. Router & Request Handling
|
|
171
|
+
**Primary File:** `server/router/router.js`
|
|
172
|
+
|
|
173
|
+
Space-agent's router has three notable patterns:
|
|
174
|
+
|
|
175
|
+
1. **Fixed explicit precedence** — Routes are matched in declaration order; no magic regex fallback
|
|
176
|
+
2. **State-version fencing** — Each request carries a `stateVersion` header; stale requests are rejected to prevent race conditions
|
|
177
|
+
3. **AsyncLocalStorage auth context** — Authentication state is propagated via Node's `AsyncLocalStorage`, so any function deep in the call stack can access the current user without passing context manually
|
|
178
|
+
|
|
179
|
+
**Borrowable for TITAN:**
|
|
180
|
+
- **State-version fencing** could prevent the race conditions TITAN sometimes hits when rapid config changes overlap with agent runs.
|
|
181
|
+
- **AsyncLocalStorage auth** would clean up TITAN's auth propagation (currently passed through many function signatures).
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
## Specific Code Patterns to Borrow
|
|
186
|
+
|
|
187
|
+
### Pattern A: Prompt Budget Enforcement
|
|
188
|
+
```javascript
|
|
189
|
+
// From onscreen_agent/execution.js (paraphrased)
|
|
190
|
+
const BUDGETS = { system: 0.30, history: 0.40, transient: 0.30 };
|
|
191
|
+
function trimToBudget(entries, maxTokens) {
|
|
192
|
+
const cached = entries.filter(e => e.tokenCount);
|
|
193
|
+
const total = cached.reduce((s, e) => s + e.tokenCount, 0);
|
|
194
|
+
if (total <= maxTokens) return entries;
|
|
195
|
+
// Trim largest contributor by at least 250 tokens
|
|
196
|
+
const overage = total - maxTokens;
|
|
197
|
+
const sorted = cached.sort((a, b) => b.tokenCount - a.tokenCount);
|
|
198
|
+
for (const entry of sorted) {
|
|
199
|
+
if (overage <= 0) break;
|
|
200
|
+
entry.tokenCount = Math.max(0, entry.tokenCount - Math.max(250, overage));
|
|
201
|
+
}
|
|
202
|
+
return entries.filter(e => e.tokenCount > 0);
|
|
203
|
+
}
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
**TITAN adaptation:** Add token budgeting to `agent.ts` message preparation. Cache token counts on `ChatMessage` objects to avoid re-counting.
|
|
207
|
+
|
|
208
|
+
### Pattern B: Skill Frontmatter Discovery
|
|
209
|
+
```javascript
|
|
210
|
+
// From skillset/skills.js (paraphrased)
|
|
211
|
+
const skills = glob('**/SKILL.md').map(path => {
|
|
212
|
+
const raw = readFileSync(path, 'utf-8');
|
|
213
|
+
const { data, content } = matter(raw);
|
|
214
|
+
return {
|
|
215
|
+
name: data.name,
|
|
216
|
+
tags: data.context_tags || [],
|
|
217
|
+
prompt: content,
|
|
218
|
+
conflicts: data.conflicts || [],
|
|
219
|
+
};
|
|
220
|
+
});
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
**TITAN adaptation:** Add `src/skills/frontmatter/` directory. Scan on boot. Merge with existing TypeScript skills.
|
|
224
|
+
|
|
225
|
+
### Pattern C: Prompt-Include Memory
|
|
226
|
+
```javascript
|
|
227
|
+
// From promptinclude/promptinclude.js (paraphrased)
|
|
228
|
+
const includes = glob('**/*.system.include.md');
|
|
229
|
+
const blocks = includes.map(path => ({
|
|
230
|
+
role: 'system',
|
|
231
|
+
content: readFileSync(path, 'utf-8'),
|
|
232
|
+
source: path, // attributed for LLM transparency
|
|
233
|
+
}));
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
**TITAN adaptation:** Add `~/.titan/includes/` directory. Auto-include `*.system.include.md` in system prompt, `*.transient.include.md` in context appendix.
|
|
237
|
+
|
|
238
|
+
### Pattern D: Deterministic Eval Harness
|
|
239
|
+
```javascript
|
|
240
|
+
// From tests/agent_llm_performance/test.mjs (paraphrased)
|
|
241
|
+
const cases = JSON.parse(readFileSync('cases.json'));
|
|
242
|
+
for (const testCase of cases) {
|
|
243
|
+
const response = await agent.run(testCase.input);
|
|
244
|
+
const result = await llm.jsonMode({
|
|
245
|
+
prompt: `Did the response satisfy: ${testCase.expected_behavior}?`,
|
|
246
|
+
schema: { passed: 'boolean', reason: 'string' }
|
|
247
|
+
});
|
|
248
|
+
results.push({ id: testCase.id, passed: result.passed, reason: result.reason });
|
|
249
|
+
}
|
|
250
|
+
writeFileSync('results.json', JSON.stringify(results, null, 2));
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
**TITAN adaptation:** Add `tests/evals/agent-widget-creation.json` with cases like: "Input: 'show backups' → Expected: calls backup_list tool, emits system:backup widget."
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
## Integration Feasibility
|
|
258
|
+
|
|
259
|
+
| Pattern | Effort | Risk | Priority |
|
|
260
|
+
|---------|--------|------|----------|
|
|
261
|
+
| Prompt budget enforcement | 1-2 days | Low — additive only | High |
|
|
262
|
+
| Skill frontmatter | 2-3 days | Low — parallel to existing skills | High |
|
|
263
|
+
| Prompt-include memory | 1 day | Low — additive only | High |
|
|
264
|
+
| Eval harness | 2-3 days | Medium — requires eval infrastructure | Medium |
|
|
265
|
+
| Client-side JS sandbox | 3-5 days | High — security implications | Low |
|
|
266
|
+
| State-version fencing | 1 day | Low — router change only | Medium |
|
|
267
|
+
| AsyncLocalStorage auth | 2 days | Medium — touches many files | Medium |
|
|
268
|
+
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
## Recommended Actions
|
|
272
|
+
|
|
273
|
+
### Immediate (This Sprint)
|
|
274
|
+
1. **Add prompt-include memory** — Create `~/.titan/includes/` and auto-load `*.system.include.md` into the system prompt
|
|
275
|
+
2. **Add skill frontmatter loader** — Scan `src/skills/**/*.md` for `SKILL.md` files and merge with TypeScript skills
|
|
276
|
+
3. **Add token budget enforcement** — Cache token counts on messages, trim by budget ratios before sending to LLM
|
|
277
|
+
|
|
278
|
+
### Short-term (Next 2 Weeks)
|
|
279
|
+
4. **Create eval harness** — Add `tests/evals/` with JSON cases for widget creation, tool calling, and safety guardrails
|
|
280
|
+
5. **Add state-version fencing** — Add `stateVersion` to config API responses; reject stale agent runs
|
|
281
|
+
|
|
282
|
+
### Long-term (Next Month)
|
|
283
|
+
6. **Experiment with code widgets** — Add a `system:code` widget type that accepts JS source and renders in a sandboxed iframe
|
|
284
|
+
7. **Adopt AsyncLocalStorage auth** — Refactor auth propagation to eliminate manual context passing
|
|
285
|
+
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
## Files Referenced
|
|
289
|
+
|
|
290
|
+
| File | Lines | Role |
|
|
291
|
+
|------|-------|------|
|
|
292
|
+
| `app/L0/_all/mod/_core/onscreen_agent/execution.js` | ~400 | Agent loop, budget enforcement, JS sandbox |
|
|
293
|
+
| `app/L0/_all/mod/_core/skillset/skills.js` | ~200 | Skill discovery, frontmatter parsing, conflict detection |
|
|
294
|
+
| `app/L0/_all/mod/_core/spaces/store.js` | ~300 | Spatial state, widget persistence |
|
|
295
|
+
| `app/L0/_all/mod/_core/spaces/layout.js` | ~150 | Grid layout, first-fit packing |
|
|
296
|
+
| `tests/agent_llm_performance/test.mjs` | ~100 | Eval harness, case runner |
|
|
297
|
+
| `server/router/router.js` | ~250 | Request routing, state versioning, auth context |
|
|
298
|
+
| `app/L0/_all/mod/_core/promptinclude/promptinclude.js` | ~100 | Prompt inclusion, file discovery |
|
|
299
|
+
| `app/L0/_all/mod/_core/memory/AGENTS.md` | ~50 | Memory architecture docs |
|
|
300
|
+
| `AGENTS.md` (root) | ~100 | Architecture contracts |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "titan-agent",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.3",
|
|
4
4
|
"description": "TITAN — Autonomous AI agent framework with self-improvement, multi-agent orchestration, 36 LLM providers, 16 channel adapters, GPU VRAM management, mesh networking, LiveKit voice, TITAN-Soma homeostatic drives, and a React Mission Control dashboard. Open-source, TypeScript, MIT licensed.",
|
|
5
5
|
"author": "Tony Elliott (https://github.com/Djtony707)",
|
|
6
6
|
"repository": {
|