@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
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ottocode/server",
|
|
3
|
+
"version": "0.1.173",
|
|
4
|
+
"description": "HTTP API server for ottocode",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./src/index.ts",
|
|
7
|
+
"types": "./src/index.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./src/index.ts",
|
|
11
|
+
"types": "./src/index.ts"
|
|
12
|
+
},
|
|
13
|
+
"./runtime/agent-registry": {
|
|
14
|
+
"import": "./src/runtime/agent-registry.ts",
|
|
15
|
+
"types": "./src/runtime/agent-registry.ts"
|
|
16
|
+
},
|
|
17
|
+
"./runtime/ask-service.ts": {
|
|
18
|
+
"import": "./src/runtime/ask-service.ts",
|
|
19
|
+
"types": "./src/runtime/ask-service.ts"
|
|
20
|
+
},
|
|
21
|
+
"./routes/ask.ts": {
|
|
22
|
+
"import": "./src/routes/ask.ts",
|
|
23
|
+
"types": "./src/routes/ask.ts"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"scripts": {
|
|
27
|
+
"dev": "bun run src/index.ts",
|
|
28
|
+
"test": "bun test",
|
|
29
|
+
"typecheck": "tsc --noEmit"
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"@ottocode/sdk": "0.1.173",
|
|
33
|
+
"@ottocode/database": "0.1.173",
|
|
34
|
+
"drizzle-orm": "^0.44.5",
|
|
35
|
+
"hono": "^4.9.9",
|
|
36
|
+
"zod": "^4.1.8"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@types/bun": "latest",
|
|
40
|
+
"typescript": "^5"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { OttoEvent } from './types.ts';
|
|
2
|
+
|
|
3
|
+
type Subscriber = (evt: OttoEvent) => void;
|
|
4
|
+
|
|
5
|
+
const subscribers = new Map<string, Set<Subscriber>>(); // sessionId -> subs
|
|
6
|
+
|
|
7
|
+
function sanitizeBigInt<T>(obj: T): T {
|
|
8
|
+
if (obj === null || obj === undefined) return obj;
|
|
9
|
+
if (typeof obj === 'bigint') return Number(obj) as T;
|
|
10
|
+
if (Array.isArray(obj)) return obj.map(sanitizeBigInt) as T;
|
|
11
|
+
if (typeof obj === 'object') {
|
|
12
|
+
const result: Record<string, unknown> = {};
|
|
13
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
14
|
+
result[key] = sanitizeBigInt(value);
|
|
15
|
+
}
|
|
16
|
+
return result as T;
|
|
17
|
+
}
|
|
18
|
+
return obj;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function publish(event: OttoEvent) {
|
|
22
|
+
const sanitizedEvent = sanitizeBigInt(event);
|
|
23
|
+
const subs = subscribers.get(event.sessionId);
|
|
24
|
+
if (!subs) return;
|
|
25
|
+
for (const sub of subs) {
|
|
26
|
+
try {
|
|
27
|
+
sub(sanitizedEvent);
|
|
28
|
+
} catch {}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function subscribe(sessionId: string, handler: Subscriber) {
|
|
33
|
+
let set = subscribers.get(sessionId);
|
|
34
|
+
if (!set) {
|
|
35
|
+
set = new Set();
|
|
36
|
+
subscribers.set(sessionId, set);
|
|
37
|
+
}
|
|
38
|
+
set.add(handler);
|
|
39
|
+
return () => {
|
|
40
|
+
set?.delete(handler);
|
|
41
|
+
if (set && set.size === 0) subscribers.delete(sessionId);
|
|
42
|
+
};
|
|
43
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export type OttoEventType =
|
|
2
|
+
| 'tool.approval.required'
|
|
3
|
+
| 'tool.approval.resolved'
|
|
4
|
+
| 'setu.payment.required'
|
|
5
|
+
| 'setu.payment.signing'
|
|
6
|
+
| 'setu.payment.complete'
|
|
7
|
+
| 'setu.payment.error'
|
|
8
|
+
| 'setu.topup.required'
|
|
9
|
+
| 'setu.topup.method_selected'
|
|
10
|
+
| 'setu.topup.cancelled'
|
|
11
|
+
| 'setu.fiat.checkout_created'
|
|
12
|
+
| 'session.created'
|
|
13
|
+
| 'session.updated'
|
|
14
|
+
| 'message.created'
|
|
15
|
+
| 'message.part.delta'
|
|
16
|
+
| 'reasoning.delta'
|
|
17
|
+
| 'message.completed'
|
|
18
|
+
| 'tool.call'
|
|
19
|
+
| 'tool.delta'
|
|
20
|
+
| 'tool.result'
|
|
21
|
+
| 'plan.updated'
|
|
22
|
+
| 'finish-step'
|
|
23
|
+
| 'usage'
|
|
24
|
+
| 'queue.updated'
|
|
25
|
+
| 'error'
|
|
26
|
+
| 'heartbeat';
|
|
27
|
+
|
|
28
|
+
export interface OttoEvent<T = unknown> {
|
|
29
|
+
type: OttoEventType;
|
|
30
|
+
sessionId: string;
|
|
31
|
+
payload?: T;
|
|
32
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
import { Hono } from 'hono';
|
|
2
|
+
import { cors } from 'hono/cors';
|
|
3
|
+
import type { ProviderId, AuthInfo } from '@ottocode/sdk';
|
|
4
|
+
import { TerminalManager } from '@ottocode/sdk';
|
|
5
|
+
import { setTerminalManager } from '@ottocode/sdk';
|
|
6
|
+
import { registerRootRoutes } from './routes/root.ts';
|
|
7
|
+
import { registerOpenApiRoute } from './routes/openapi.ts';
|
|
8
|
+
import { registerSessionsRoutes } from './routes/sessions.ts';
|
|
9
|
+
import { registerSessionMessagesRoutes } from './routes/session-messages.ts';
|
|
10
|
+
import { registerSessionStreamRoute } from './routes/session-stream.ts';
|
|
11
|
+
import { registerAskRoutes } from './routes/ask.ts';
|
|
12
|
+
import { registerConfigRoutes } from './routes/config/index.ts';
|
|
13
|
+
import { registerFilesRoutes } from './routes/files.ts';
|
|
14
|
+
import { registerGitRoutes } from './routes/git/index.ts';
|
|
15
|
+
import { registerTerminalsRoutes } from './routes/terminals.ts';
|
|
16
|
+
import { registerSessionFilesRoutes } from './routes/session-files.ts';
|
|
17
|
+
import { registerBranchRoutes } from './routes/branch.ts';
|
|
18
|
+
import { registerResearchRoutes } from './routes/research.ts';
|
|
19
|
+
import { registerSessionApprovalRoute } from './routes/session-approval.ts';
|
|
20
|
+
import { registerSetuRoutes } from './routes/setu.ts';
|
|
21
|
+
import { registerAuthRoutes } from './routes/auth.ts';
|
|
22
|
+
import type { AgentConfigEntry } from './runtime/agent/registry.ts';
|
|
23
|
+
|
|
24
|
+
const globalTerminalManager = new TerminalManager();
|
|
25
|
+
setTerminalManager(globalTerminalManager);
|
|
26
|
+
|
|
27
|
+
function initApp() {
|
|
28
|
+
const app = new Hono();
|
|
29
|
+
|
|
30
|
+
// Enable CORS for localhost and local network access
|
|
31
|
+
app.use(
|
|
32
|
+
'*',
|
|
33
|
+
cors({
|
|
34
|
+
origin: (origin) => {
|
|
35
|
+
// Allow all localhost and 127.0.0.1 on any port
|
|
36
|
+
if (
|
|
37
|
+
origin.startsWith('http://localhost:') ||
|
|
38
|
+
origin.startsWith('http://127.0.0.1:') ||
|
|
39
|
+
origin.startsWith('https://localhost:') ||
|
|
40
|
+
origin.startsWith('https://127.0.0.1:')
|
|
41
|
+
) {
|
|
42
|
+
return origin;
|
|
43
|
+
}
|
|
44
|
+
// Allow local network IPs (192.168.x.x, 10.x.x.x, 172.16-31.x.x)
|
|
45
|
+
const localNetworkPattern =
|
|
46
|
+
/^https?:\/\/(192\.168\.\d{1,3}\.\d{1,3}|10\.\d{1,3}\.\d{1,3}\.\d{1,3}|172\.(1[6-9]|2\d|3[01])\.\d{1,3}\.\d{1,3}):\d+$/;
|
|
47
|
+
if (localNetworkPattern.test(origin)) {
|
|
48
|
+
return origin;
|
|
49
|
+
}
|
|
50
|
+
// Default to allowing the origin (can be restricted in production)
|
|
51
|
+
return origin;
|
|
52
|
+
},
|
|
53
|
+
allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
|
|
54
|
+
allowHeaders: ['Content-Type', 'Authorization', 'X-Requested-With'],
|
|
55
|
+
exposeHeaders: ['Content-Length', 'X-Request-Id'],
|
|
56
|
+
credentials: true,
|
|
57
|
+
maxAge: 600,
|
|
58
|
+
}),
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
registerRootRoutes(app);
|
|
62
|
+
registerOpenApiRoute(app);
|
|
63
|
+
registerSessionsRoutes(app);
|
|
64
|
+
registerSessionApprovalRoute(app);
|
|
65
|
+
registerSessionMessagesRoutes(app);
|
|
66
|
+
registerSessionStreamRoute(app);
|
|
67
|
+
registerAskRoutes(app);
|
|
68
|
+
registerConfigRoutes(app);
|
|
69
|
+
registerFilesRoutes(app);
|
|
70
|
+
registerGitRoutes(app);
|
|
71
|
+
registerTerminalsRoutes(app, globalTerminalManager);
|
|
72
|
+
registerSessionFilesRoutes(app);
|
|
73
|
+
registerBranchRoutes(app);
|
|
74
|
+
registerResearchRoutes(app);
|
|
75
|
+
registerSetuRoutes(app);
|
|
76
|
+
registerAuthRoutes(app);
|
|
77
|
+
|
|
78
|
+
return app;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const app = initApp();
|
|
82
|
+
|
|
83
|
+
export default {
|
|
84
|
+
port: 0,
|
|
85
|
+
fetch: app.fetch,
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
export function createApp() {
|
|
89
|
+
return app;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export type StandaloneAppConfig = {
|
|
93
|
+
provider?: ProviderId;
|
|
94
|
+
model?: string;
|
|
95
|
+
defaultAgent?: string;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
export function createStandaloneApp(_config?: StandaloneAppConfig) {
|
|
99
|
+
const honoApp = new Hono();
|
|
100
|
+
|
|
101
|
+
// Enable CORS for localhost and local network access
|
|
102
|
+
honoApp.use(
|
|
103
|
+
'*',
|
|
104
|
+
cors({
|
|
105
|
+
origin: (origin) => {
|
|
106
|
+
// Allow all localhost and 127.0.0.1 on any port
|
|
107
|
+
if (
|
|
108
|
+
origin.startsWith('http://localhost:') ||
|
|
109
|
+
origin.startsWith('http://127.0.0.1:') ||
|
|
110
|
+
origin.startsWith('https://localhost:') ||
|
|
111
|
+
origin.startsWith('https://127.0.0.1:')
|
|
112
|
+
) {
|
|
113
|
+
return origin;
|
|
114
|
+
}
|
|
115
|
+
// Allow local network IPs (192.168.x.x, 10.x.x.x, 172.16-31.x.x)
|
|
116
|
+
const localNetworkPattern =
|
|
117
|
+
/^https?:\/\/(192\.168\.\d{1,3}\.\d{1,3}|10\.\d{1,3}\.\d{1,3}\.\d{1,3}|172\.(1[6-9]|2\d|3[01])\.\d{1,3}\.\d{1,3}):\d+$/;
|
|
118
|
+
if (localNetworkPattern.test(origin)) {
|
|
119
|
+
return origin;
|
|
120
|
+
}
|
|
121
|
+
// Default to allowing the origin
|
|
122
|
+
return origin;
|
|
123
|
+
},
|
|
124
|
+
allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
|
|
125
|
+
allowHeaders: ['Content-Type', 'Authorization', 'X-Requested-With'],
|
|
126
|
+
exposeHeaders: ['Content-Length', 'X-Request-Id'],
|
|
127
|
+
credentials: true,
|
|
128
|
+
maxAge: 600,
|
|
129
|
+
}),
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
registerRootRoutes(honoApp);
|
|
133
|
+
registerOpenApiRoute(honoApp);
|
|
134
|
+
registerSessionsRoutes(honoApp);
|
|
135
|
+
registerSessionApprovalRoute(honoApp);
|
|
136
|
+
registerSessionMessagesRoutes(honoApp);
|
|
137
|
+
registerSessionStreamRoute(honoApp);
|
|
138
|
+
registerAskRoutes(honoApp);
|
|
139
|
+
registerConfigRoutes(honoApp);
|
|
140
|
+
registerFilesRoutes(honoApp);
|
|
141
|
+
registerGitRoutes(honoApp);
|
|
142
|
+
registerTerminalsRoutes(honoApp, globalTerminalManager);
|
|
143
|
+
registerSessionFilesRoutes(honoApp);
|
|
144
|
+
registerBranchRoutes(honoApp);
|
|
145
|
+
registerResearchRoutes(honoApp);
|
|
146
|
+
registerSetuRoutes(honoApp);
|
|
147
|
+
registerAuthRoutes(honoApp);
|
|
148
|
+
|
|
149
|
+
return honoApp;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Embedded app configuration with hybrid fallback:
|
|
154
|
+
* 1. Injected config (highest priority)
|
|
155
|
+
* 2. Environment variables
|
|
156
|
+
* 3. auth.json/config.json files (fallback)
|
|
157
|
+
*
|
|
158
|
+
* All fields are optional - if not provided, falls back to files/env
|
|
159
|
+
*/
|
|
160
|
+
export type EmbeddedAppConfig = {
|
|
161
|
+
/** Primary provider (optional - falls back to config.json or env) */
|
|
162
|
+
provider?: ProviderId;
|
|
163
|
+
/** Primary model (optional - falls back to config.json) */
|
|
164
|
+
model?: string;
|
|
165
|
+
/** Primary API key (optional - falls back to env vars or auth.json) */
|
|
166
|
+
apiKey?: string;
|
|
167
|
+
/** Default agent (optional - falls back to config.json) */
|
|
168
|
+
agent?: string;
|
|
169
|
+
/** Multi-provider auth (optional - falls back to auth.json) */
|
|
170
|
+
auth?: Record<string, { apiKey: string } | AuthInfo>;
|
|
171
|
+
/** Custom agents (optional - falls back to .otto/agents/) */
|
|
172
|
+
agents?: Record<
|
|
173
|
+
string,
|
|
174
|
+
Omit<AgentConfigEntry, 'tools'> & { tools?: readonly string[] | string[] }
|
|
175
|
+
>;
|
|
176
|
+
/** Default settings (optional - falls back to config.json) */
|
|
177
|
+
defaults?: {
|
|
178
|
+
provider?: ProviderId;
|
|
179
|
+
model?: string;
|
|
180
|
+
agent?: string;
|
|
181
|
+
};
|
|
182
|
+
/** Additional CORS origins for proxies/Tailscale (e.g., ['https://myapp.ts.net', 'https://example.com']) */
|
|
183
|
+
corsOrigins?: string[];
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
export function createEmbeddedApp(config: EmbeddedAppConfig = {}) {
|
|
187
|
+
const honoApp = new Hono();
|
|
188
|
+
|
|
189
|
+
// Store injected config in Hono context for routes to access
|
|
190
|
+
// Config can be empty - routes will fall back to files/env
|
|
191
|
+
honoApp.use('*', async (c, next) => {
|
|
192
|
+
c.set('embeddedConfig', config);
|
|
193
|
+
await next();
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
// Enable CORS for localhost and local network access
|
|
197
|
+
honoApp.use(
|
|
198
|
+
'*',
|
|
199
|
+
cors({
|
|
200
|
+
origin: (origin) => {
|
|
201
|
+
// Allow all localhost and 127.0.0.1 on any port
|
|
202
|
+
if (
|
|
203
|
+
origin.startsWith('http://localhost:') ||
|
|
204
|
+
origin.startsWith('http://127.0.0.1:') ||
|
|
205
|
+
origin.startsWith('https://localhost:') ||
|
|
206
|
+
origin.startsWith('https://127.0.0.1:')
|
|
207
|
+
) {
|
|
208
|
+
return origin;
|
|
209
|
+
}
|
|
210
|
+
// Allow local network IPs (192.168.x.x, 10.x.x.x, 172.16-31.x.x)
|
|
211
|
+
const localNetworkPattern =
|
|
212
|
+
/^https?:\/\/(192\.168\.\d{1,3}\.\d{1,3}|10\.\d{1,3}\.\d{1,3}\.\d{1,3}|172\.(1[6-9]|2\d|3[01])\.\d{1,3}\.\d{1,3}):\d+$/;
|
|
213
|
+
if (localNetworkPattern.test(origin)) {
|
|
214
|
+
return origin;
|
|
215
|
+
}
|
|
216
|
+
// Allow custom CORS origins (for Tailscale, proxies, etc.)
|
|
217
|
+
if (config.corsOrigins?.includes(origin)) {
|
|
218
|
+
return origin;
|
|
219
|
+
}
|
|
220
|
+
// Default to allowing the origin
|
|
221
|
+
return origin;
|
|
222
|
+
},
|
|
223
|
+
allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
|
|
224
|
+
allowHeaders: ['Content-Type', 'Authorization', 'X-Requested-With'],
|
|
225
|
+
exposeHeaders: ['Content-Length', 'X-Request-Id'],
|
|
226
|
+
credentials: true,
|
|
227
|
+
maxAge: 600,
|
|
228
|
+
}),
|
|
229
|
+
);
|
|
230
|
+
|
|
231
|
+
registerRootRoutes(honoApp);
|
|
232
|
+
registerOpenApiRoute(honoApp);
|
|
233
|
+
registerSessionsRoutes(honoApp);
|
|
234
|
+
registerSessionApprovalRoute(honoApp);
|
|
235
|
+
registerSessionMessagesRoutes(honoApp);
|
|
236
|
+
registerSessionStreamRoute(honoApp);
|
|
237
|
+
registerAskRoutes(honoApp);
|
|
238
|
+
registerConfigRoutes(honoApp);
|
|
239
|
+
registerFilesRoutes(honoApp);
|
|
240
|
+
registerGitRoutes(honoApp);
|
|
241
|
+
registerTerminalsRoutes(honoApp, globalTerminalManager);
|
|
242
|
+
registerSessionFilesRoutes(honoApp);
|
|
243
|
+
registerBranchRoutes(honoApp);
|
|
244
|
+
registerResearchRoutes(honoApp);
|
|
245
|
+
registerSetuRoutes(honoApp);
|
|
246
|
+
registerAuthRoutes(honoApp);
|
|
247
|
+
|
|
248
|
+
return honoApp;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
export {
|
|
252
|
+
resolveAgentConfig,
|
|
253
|
+
defaultToolsForAgent,
|
|
254
|
+
} from './runtime/agent/registry.ts';
|
|
255
|
+
export {
|
|
256
|
+
composeSystemPrompt,
|
|
257
|
+
type ComposedSystemPrompt,
|
|
258
|
+
} from './runtime/prompt/builder.ts';
|
|
259
|
+
export {
|
|
260
|
+
AskServiceError,
|
|
261
|
+
handleAskRequest,
|
|
262
|
+
deriveStatusFromMessage,
|
|
263
|
+
inferStatus,
|
|
264
|
+
} from './runtime/ask/service.ts';
|
|
265
|
+
export { registerSessionsRoutes } from './routes/sessions.ts';
|
|
266
|
+
export { registerAskRoutes } from './routes/ask.ts';
|
|
267
|
+
export {
|
|
268
|
+
BUILTIN_AGENTS,
|
|
269
|
+
BUILTIN_TOOLS,
|
|
270
|
+
type BuiltinAgent,
|
|
271
|
+
type BuiltinTool,
|
|
272
|
+
} from './presets.ts';
|
|
273
|
+
|
|
274
|
+
// Export debug state management
|
|
275
|
+
export {
|
|
276
|
+
setDebugEnabled,
|
|
277
|
+
isDebugEnabled,
|
|
278
|
+
setTraceEnabled,
|
|
279
|
+
isTraceEnabled,
|
|
280
|
+
} from './runtime/debug/state.ts';
|
|
281
|
+
export { logger } from '@ottocode/sdk';
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
export function projectQueryParam() {
|
|
2
|
+
return {
|
|
3
|
+
in: 'query',
|
|
4
|
+
name: 'project',
|
|
5
|
+
required: false,
|
|
6
|
+
schema: { type: 'string' },
|
|
7
|
+
description:
|
|
8
|
+
'Project root override (defaults to current working directory).',
|
|
9
|
+
} as const;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function sessionIdParam() {
|
|
13
|
+
return {
|
|
14
|
+
in: 'path',
|
|
15
|
+
name: 'id',
|
|
16
|
+
required: true,
|
|
17
|
+
schema: { type: 'string' },
|
|
18
|
+
} as const;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function withoutParam() {
|
|
22
|
+
return {
|
|
23
|
+
in: 'query',
|
|
24
|
+
name: 'without',
|
|
25
|
+
required: false,
|
|
26
|
+
schema: { type: 'string', enum: ['parts'] },
|
|
27
|
+
description:
|
|
28
|
+
'Exclude parts from the response. By default, parts are included.',
|
|
29
|
+
} as const;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function errorResponse() {
|
|
33
|
+
return {
|
|
34
|
+
description: 'Bad Request',
|
|
35
|
+
content: {
|
|
36
|
+
'application/json': {
|
|
37
|
+
schema: {
|
|
38
|
+
type: 'object',
|
|
39
|
+
properties: { error: { type: 'string' } },
|
|
40
|
+
required: ['error'],
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
} as const;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function gitErrorResponse() {
|
|
48
|
+
return {
|
|
49
|
+
description: 'Error',
|
|
50
|
+
content: {
|
|
51
|
+
'application/json': {
|
|
52
|
+
schema: {
|
|
53
|
+
type: 'object',
|
|
54
|
+
properties: {
|
|
55
|
+
status: { type: 'string', enum: ['error'] },
|
|
56
|
+
error: { type: 'string' },
|
|
57
|
+
code: { type: 'string' },
|
|
58
|
+
},
|
|
59
|
+
required: ['status', 'error'],
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
} as const;
|
|
64
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { errorResponse, projectQueryParam } from '../helpers';
|
|
2
|
+
|
|
3
|
+
export const askPaths = {
|
|
4
|
+
'/v1/ask': {
|
|
5
|
+
post: {
|
|
6
|
+
tags: ['ask'],
|
|
7
|
+
operationId: 'ask',
|
|
8
|
+
summary: 'Send a prompt using the ask service',
|
|
9
|
+
description:
|
|
10
|
+
'Streamlined endpoint used by the CLI to send prompts and receive assistant responses. Creates sessions as needed and reuses the last session when requested.',
|
|
11
|
+
parameters: [projectQueryParam()],
|
|
12
|
+
requestBody: {
|
|
13
|
+
required: true,
|
|
14
|
+
content: {
|
|
15
|
+
'application/json': {
|
|
16
|
+
schema: {
|
|
17
|
+
type: 'object',
|
|
18
|
+
required: ['prompt'],
|
|
19
|
+
properties: {
|
|
20
|
+
prompt: {
|
|
21
|
+
type: 'string',
|
|
22
|
+
description: 'User prompt to send to the assistant.',
|
|
23
|
+
},
|
|
24
|
+
agent: {
|
|
25
|
+
type: 'string',
|
|
26
|
+
description: 'Optional agent name to use for this request.',
|
|
27
|
+
},
|
|
28
|
+
provider: {
|
|
29
|
+
$ref: '#/components/schemas/Provider',
|
|
30
|
+
description:
|
|
31
|
+
'Optional provider override. When omitted the agent and config defaults apply.',
|
|
32
|
+
},
|
|
33
|
+
model: {
|
|
34
|
+
type: 'string',
|
|
35
|
+
description:
|
|
36
|
+
'Optional model override for the selected provider.',
|
|
37
|
+
},
|
|
38
|
+
sessionId: {
|
|
39
|
+
type: 'string',
|
|
40
|
+
description: 'Send the prompt to a specific session.',
|
|
41
|
+
},
|
|
42
|
+
last: {
|
|
43
|
+
type: 'boolean',
|
|
44
|
+
description:
|
|
45
|
+
'If true, reuse the most recent session for the project.',
|
|
46
|
+
},
|
|
47
|
+
jsonMode: {
|
|
48
|
+
type: 'boolean',
|
|
49
|
+
description:
|
|
50
|
+
'Request structured JSON output when supported by the agent.',
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
responses: {
|
|
58
|
+
202: {
|
|
59
|
+
description: 'Accepted',
|
|
60
|
+
content: {
|
|
61
|
+
'application/json': {
|
|
62
|
+
schema: { $ref: '#/components/schemas/AskResponse' },
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
400: errorResponse(),
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
} as const;
|