@ottocode/server 0.1.173
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/package.json +42 -0
- package/src/events/bus.ts +43 -0
- package/src/events/types.ts +32 -0
- package/src/index.ts +281 -0
- package/src/openapi/helpers.ts +64 -0
- package/src/openapi/paths/ask.ts +70 -0
- package/src/openapi/paths/config.ts +218 -0
- package/src/openapi/paths/files.ts +72 -0
- package/src/openapi/paths/git.ts +457 -0
- package/src/openapi/paths/messages.ts +92 -0
- package/src/openapi/paths/sessions.ts +90 -0
- package/src/openapi/paths/setu.ts +154 -0
- package/src/openapi/paths/stream.ts +26 -0
- package/src/openapi/paths/terminals.ts +226 -0
- package/src/openapi/schemas.ts +345 -0
- package/src/openapi/spec.ts +49 -0
- package/src/presets.ts +85 -0
- package/src/routes/ask.ts +113 -0
- package/src/routes/auth.ts +592 -0
- package/src/routes/branch.ts +106 -0
- package/src/routes/config/agents.ts +44 -0
- package/src/routes/config/cwd.ts +21 -0
- package/src/routes/config/defaults.ts +45 -0
- package/src/routes/config/index.ts +16 -0
- package/src/routes/config/main.ts +73 -0
- package/src/routes/config/models.ts +139 -0
- package/src/routes/config/providers.ts +46 -0
- package/src/routes/config/utils.ts +120 -0
- package/src/routes/files.ts +218 -0
- package/src/routes/git/branch.ts +75 -0
- package/src/routes/git/commit.ts +209 -0
- package/src/routes/git/diff.ts +137 -0
- package/src/routes/git/index.ts +18 -0
- package/src/routes/git/push.ts +160 -0
- package/src/routes/git/schemas.ts +48 -0
- package/src/routes/git/staging.ts +208 -0
- package/src/routes/git/status.ts +83 -0
- package/src/routes/git/types.ts +31 -0
- package/src/routes/git/utils.ts +249 -0
- package/src/routes/openapi.ts +6 -0
- package/src/routes/research.ts +392 -0
- package/src/routes/root.ts +5 -0
- package/src/routes/session-approval.ts +63 -0
- package/src/routes/session-files.ts +387 -0
- package/src/routes/session-messages.ts +170 -0
- package/src/routes/session-stream.ts +61 -0
- package/src/routes/sessions.ts +814 -0
- package/src/routes/setu.ts +346 -0
- package/src/routes/terminals.ts +227 -0
- package/src/runtime/agent/registry.ts +351 -0
- package/src/runtime/agent/runner-reasoning.ts +108 -0
- package/src/runtime/agent/runner-setup.ts +257 -0
- package/src/runtime/agent/runner.ts +375 -0
- package/src/runtime/agent-registry.ts +6 -0
- package/src/runtime/ask/service.ts +369 -0
- package/src/runtime/context/environment.ts +202 -0
- package/src/runtime/debug/index.ts +117 -0
- package/src/runtime/debug/state.ts +140 -0
- package/src/runtime/errors/api-error.ts +192 -0
- package/src/runtime/errors/handling.ts +199 -0
- package/src/runtime/message/compaction-auto.ts +154 -0
- package/src/runtime/message/compaction-context.ts +101 -0
- package/src/runtime/message/compaction-detect.ts +26 -0
- package/src/runtime/message/compaction-limits.ts +37 -0
- package/src/runtime/message/compaction-mark.ts +111 -0
- package/src/runtime/message/compaction-prune.ts +75 -0
- package/src/runtime/message/compaction.ts +21 -0
- package/src/runtime/message/history-builder.ts +266 -0
- package/src/runtime/message/service.ts +468 -0
- package/src/runtime/message/tool-history-tracker.ts +204 -0
- package/src/runtime/prompt/builder.ts +167 -0
- package/src/runtime/provider/anthropic.ts +50 -0
- package/src/runtime/provider/copilot.ts +12 -0
- package/src/runtime/provider/google.ts +8 -0
- package/src/runtime/provider/index.ts +60 -0
- package/src/runtime/provider/moonshot.ts +8 -0
- package/src/runtime/provider/oauth-adapter.ts +237 -0
- package/src/runtime/provider/openai.ts +18 -0
- package/src/runtime/provider/opencode.ts +7 -0
- package/src/runtime/provider/openrouter.ts +7 -0
- package/src/runtime/provider/selection.ts +118 -0
- package/src/runtime/provider/setu.ts +126 -0
- package/src/runtime/provider/zai.ts +16 -0
- package/src/runtime/session/branch.ts +280 -0
- package/src/runtime/session/db-operations.ts +285 -0
- package/src/runtime/session/manager.ts +99 -0
- package/src/runtime/session/queue.ts +243 -0
- package/src/runtime/stream/abort-handler.ts +65 -0
- package/src/runtime/stream/error-handler.ts +371 -0
- package/src/runtime/stream/finish-handler.ts +101 -0
- package/src/runtime/stream/handlers.ts +5 -0
- package/src/runtime/stream/step-finish.ts +93 -0
- package/src/runtime/stream/types.ts +25 -0
- package/src/runtime/tools/approval.ts +180 -0
- package/src/runtime/tools/context.ts +83 -0
- package/src/runtime/tools/mapping.ts +154 -0
- package/src/runtime/tools/setup.ts +44 -0
- package/src/runtime/topup/manager.ts +110 -0
- package/src/runtime/utils/cwd.ts +69 -0
- package/src/runtime/utils/token.ts +35 -0
- package/src/tools/adapter.ts +634 -0
- package/src/tools/database/get-parent-session.ts +183 -0
- package/src/tools/database/get-session-context.ts +161 -0
- package/src/tools/database/index.ts +42 -0
- package/src/tools/database/present-session-links.ts +47 -0
- package/src/tools/database/query-messages.ts +160 -0
- package/src/tools/database/query-sessions.ts +126 -0
- package/src/tools/database/search-history.ts +135 -0
- package/src/types/sql-imports.d.ts +5 -0
- package/sst-env.d.ts +8 -0
- package/tsconfig.json +7 -0
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { tool } from 'ai';
|
|
2
|
+
import { z } from 'zod/v3';
|
|
3
|
+
import { getDb } from '@ottocode/database';
|
|
4
|
+
import { sessions, messages } from '@ottocode/database/schema';
|
|
5
|
+
import { eq, desc, asc, gte, lte, and, count } from 'drizzle-orm';
|
|
6
|
+
|
|
7
|
+
const inputSchema = z.object({
|
|
8
|
+
limit: z
|
|
9
|
+
.number()
|
|
10
|
+
.min(1)
|
|
11
|
+
.max(100)
|
|
12
|
+
.default(20)
|
|
13
|
+
.describe('Max sessions to return'),
|
|
14
|
+
offset: z.number().min(0).default(0).describe('Offset for pagination'),
|
|
15
|
+
agent: z.string().optional().describe('Filter by agent type'),
|
|
16
|
+
startDate: z
|
|
17
|
+
.string()
|
|
18
|
+
.optional()
|
|
19
|
+
.describe('Filter sessions created after this ISO date'),
|
|
20
|
+
endDate: z
|
|
21
|
+
.string()
|
|
22
|
+
.optional()
|
|
23
|
+
.describe('Filter sessions created before this ISO date'),
|
|
24
|
+
orderBy: z
|
|
25
|
+
.enum(['created_at', 'last_active_at', 'total_tokens'])
|
|
26
|
+
.default('last_active_at')
|
|
27
|
+
.describe('Sort field'),
|
|
28
|
+
orderDir: z.enum(['asc', 'desc']).default('desc').describe('Sort direction'),
|
|
29
|
+
sessionType: z
|
|
30
|
+
.enum(['main', 'research', 'all'])
|
|
31
|
+
.default('main')
|
|
32
|
+
.describe('Filter by session type'),
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
export function buildQuerySessionsTool(projectRoot: string) {
|
|
36
|
+
return {
|
|
37
|
+
name: 'query_sessions',
|
|
38
|
+
tool: tool({
|
|
39
|
+
description:
|
|
40
|
+
'Search and list sessions from the local database. Use to find past conversations, check what work was done, or locate specific sessions.',
|
|
41
|
+
inputSchema,
|
|
42
|
+
async execute(input) {
|
|
43
|
+
const db = await getDb(projectRoot);
|
|
44
|
+
|
|
45
|
+
const conditions = [eq(sessions.projectPath, projectRoot)];
|
|
46
|
+
|
|
47
|
+
if (input.sessionType !== 'all') {
|
|
48
|
+
conditions.push(eq(sessions.sessionType, input.sessionType));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (input.agent) {
|
|
52
|
+
conditions.push(eq(sessions.agent, input.agent));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (input.startDate) {
|
|
56
|
+
const startTs = new Date(input.startDate).getTime();
|
|
57
|
+
conditions.push(gte(sessions.createdAt, startTs));
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (input.endDate) {
|
|
61
|
+
const endTs = new Date(input.endDate).getTime();
|
|
62
|
+
conditions.push(lte(sessions.createdAt, endTs));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const orderField =
|
|
66
|
+
input.orderBy === 'created_at'
|
|
67
|
+
? sessions.createdAt
|
|
68
|
+
: input.orderBy === 'total_tokens'
|
|
69
|
+
? sessions.totalInputTokens
|
|
70
|
+
: sessions.lastActiveAt;
|
|
71
|
+
|
|
72
|
+
const orderFn = input.orderDir === 'asc' ? asc : desc;
|
|
73
|
+
|
|
74
|
+
const rows = await db
|
|
75
|
+
.select({
|
|
76
|
+
id: sessions.id,
|
|
77
|
+
title: sessions.title,
|
|
78
|
+
agent: sessions.agent,
|
|
79
|
+
provider: sessions.provider,
|
|
80
|
+
model: sessions.model,
|
|
81
|
+
createdAt: sessions.createdAt,
|
|
82
|
+
lastActiveAt: sessions.lastActiveAt,
|
|
83
|
+
totalInputTokens: sessions.totalInputTokens,
|
|
84
|
+
totalOutputTokens: sessions.totalOutputTokens,
|
|
85
|
+
totalCachedTokens: sessions.totalCachedTokens,
|
|
86
|
+
totalCacheCreationTokens: sessions.totalCacheCreationTokens,
|
|
87
|
+
sessionType: sessions.sessionType,
|
|
88
|
+
parentSessionId: sessions.parentSessionId,
|
|
89
|
+
})
|
|
90
|
+
.from(sessions)
|
|
91
|
+
.where(and(...conditions))
|
|
92
|
+
.orderBy(orderFn(orderField), desc(sessions.createdAt))
|
|
93
|
+
.limit(input.limit)
|
|
94
|
+
.offset(input.offset);
|
|
95
|
+
|
|
96
|
+
const countResult = await db
|
|
97
|
+
.select({ total: count() })
|
|
98
|
+
.from(sessions)
|
|
99
|
+
.where(and(...conditions));
|
|
100
|
+
|
|
101
|
+
const total = countResult[0]?.total ?? 0;
|
|
102
|
+
|
|
103
|
+
const sessionsWithCounts = await Promise.all(
|
|
104
|
+
rows.map(async (row) => {
|
|
105
|
+
const msgCount = await db
|
|
106
|
+
.select({ count: count() })
|
|
107
|
+
.from(messages)
|
|
108
|
+
.where(eq(messages.sessionId, row.id));
|
|
109
|
+
return {
|
|
110
|
+
...row,
|
|
111
|
+
messageCount: msgCount[0]?.count ?? 0,
|
|
112
|
+
};
|
|
113
|
+
}),
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
return {
|
|
117
|
+
ok: true,
|
|
118
|
+
sessions: sessionsWithCounts,
|
|
119
|
+
total,
|
|
120
|
+
limit: input.limit,
|
|
121
|
+
offset: input.offset,
|
|
122
|
+
};
|
|
123
|
+
},
|
|
124
|
+
}),
|
|
125
|
+
};
|
|
126
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { tool } from 'ai';
|
|
2
|
+
import { z } from 'zod/v3';
|
|
3
|
+
import { getDb } from '@ottocode/database';
|
|
4
|
+
import { sessions, messages, messageParts } from '@ottocode/database/schema';
|
|
5
|
+
import { eq, like, and } from 'drizzle-orm';
|
|
6
|
+
|
|
7
|
+
const inputSchema = z.object({
|
|
8
|
+
query: z.string().min(1).describe('Search term to find in message content'),
|
|
9
|
+
limit: z
|
|
10
|
+
.number()
|
|
11
|
+
.min(1)
|
|
12
|
+
.max(50)
|
|
13
|
+
.default(20)
|
|
14
|
+
.describe('Max results to return'),
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
export function buildSearchHistoryTool(projectRoot: string) {
|
|
18
|
+
return {
|
|
19
|
+
name: 'search_history',
|
|
20
|
+
tool: tool({
|
|
21
|
+
description:
|
|
22
|
+
'Full-text search across all message content in session history. Find past conversations, solutions, or discussions about specific topics.',
|
|
23
|
+
inputSchema,
|
|
24
|
+
async execute(input) {
|
|
25
|
+
const db = await getDb(projectRoot);
|
|
26
|
+
|
|
27
|
+
const projectSessionIds = await db
|
|
28
|
+
.select({ id: sessions.id })
|
|
29
|
+
.from(sessions)
|
|
30
|
+
.where(eq(sessions.projectPath, projectRoot));
|
|
31
|
+
|
|
32
|
+
const sessionIdSet = new Set(projectSessionIds.map((s) => s.id));
|
|
33
|
+
|
|
34
|
+
if (sessionIdSet.size === 0) {
|
|
35
|
+
return {
|
|
36
|
+
ok: true,
|
|
37
|
+
results: [],
|
|
38
|
+
total: 0,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const searchPattern = `%${input.query}%`;
|
|
43
|
+
|
|
44
|
+
const matchingParts = await db
|
|
45
|
+
.select({
|
|
46
|
+
id: messageParts.id,
|
|
47
|
+
messageId: messageParts.messageId,
|
|
48
|
+
content: messageParts.content,
|
|
49
|
+
type: messageParts.type,
|
|
50
|
+
})
|
|
51
|
+
.from(messageParts)
|
|
52
|
+
.where(
|
|
53
|
+
and(
|
|
54
|
+
eq(messageParts.type, 'text'),
|
|
55
|
+
like(messageParts.content, searchPattern),
|
|
56
|
+
),
|
|
57
|
+
)
|
|
58
|
+
.limit(input.limit * 3);
|
|
59
|
+
|
|
60
|
+
const results: Array<{
|
|
61
|
+
sessionId: string;
|
|
62
|
+
sessionTitle: string | null;
|
|
63
|
+
messageId: string;
|
|
64
|
+
role: string;
|
|
65
|
+
matchedContent: string;
|
|
66
|
+
createdAt: number;
|
|
67
|
+
}> = [];
|
|
68
|
+
|
|
69
|
+
for (const part of matchingParts) {
|
|
70
|
+
if (results.length >= input.limit) break;
|
|
71
|
+
|
|
72
|
+
const msgRows = await db
|
|
73
|
+
.select({
|
|
74
|
+
id: messages.id,
|
|
75
|
+
sessionId: messages.sessionId,
|
|
76
|
+
role: messages.role,
|
|
77
|
+
createdAt: messages.createdAt,
|
|
78
|
+
})
|
|
79
|
+
.from(messages)
|
|
80
|
+
.where(eq(messages.id, part.messageId))
|
|
81
|
+
.limit(1);
|
|
82
|
+
|
|
83
|
+
if (msgRows.length === 0) continue;
|
|
84
|
+
|
|
85
|
+
const msg = msgRows[0];
|
|
86
|
+
|
|
87
|
+
if (!sessionIdSet.has(msg.sessionId)) continue;
|
|
88
|
+
|
|
89
|
+
const sessionRows = await db
|
|
90
|
+
.select({ title: sessions.title })
|
|
91
|
+
.from(sessions)
|
|
92
|
+
.where(eq(sessions.id, msg.sessionId))
|
|
93
|
+
.limit(1);
|
|
94
|
+
|
|
95
|
+
const content = part.content ?? '';
|
|
96
|
+
const queryLower = input.query.toLowerCase();
|
|
97
|
+
const contentLower = content.toLowerCase();
|
|
98
|
+
const matchIndex = contentLower.indexOf(queryLower);
|
|
99
|
+
|
|
100
|
+
let matchedContent: string;
|
|
101
|
+
if (matchIndex >= 0) {
|
|
102
|
+
const start = Math.max(0, matchIndex - 50);
|
|
103
|
+
const end = Math.min(
|
|
104
|
+
content.length,
|
|
105
|
+
matchIndex + input.query.length + 50,
|
|
106
|
+
);
|
|
107
|
+
const prefix = start > 0 ? '...' : '';
|
|
108
|
+
const suffix = end < content.length ? '...' : '';
|
|
109
|
+
matchedContent = prefix + content.slice(start, end) + suffix;
|
|
110
|
+
} else {
|
|
111
|
+
matchedContent =
|
|
112
|
+
content.slice(0, 150) + (content.length > 150 ? '...' : '');
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
results.push({
|
|
116
|
+
sessionId: msg.sessionId,
|
|
117
|
+
sessionTitle: sessionRows[0]?.title ?? null,
|
|
118
|
+
messageId: msg.id,
|
|
119
|
+
role: msg.role,
|
|
120
|
+
matchedContent,
|
|
121
|
+
createdAt: msg.createdAt,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
results.sort((a, b) => b.createdAt - a.createdAt);
|
|
126
|
+
|
|
127
|
+
return {
|
|
128
|
+
ok: true,
|
|
129
|
+
results,
|
|
130
|
+
total: results.length,
|
|
131
|
+
};
|
|
132
|
+
},
|
|
133
|
+
}),
|
|
134
|
+
};
|
|
135
|
+
}
|
package/sst-env.d.ts
ADDED