@glbgpt/cli 0.1.0-test.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +111 -0
- package/dist/src/auth/authClient.d.ts +32 -0
- package/dist/src/auth/authClient.js +88 -0
- package/dist/src/auth/authClient.js.map +1 -0
- package/dist/src/auth/credentialStore.d.ts +22 -0
- package/dist/src/auth/credentialStore.js +51 -0
- package/dist/src/auth/credentialStore.js.map +1 -0
- package/dist/src/auth/loginFlow.d.ts +30 -0
- package/dist/src/auth/loginFlow.js +43 -0
- package/dist/src/auth/loginFlow.js.map +1 -0
- package/dist/src/auth/loopbackServer.d.ts +41 -0
- package/dist/src/auth/loopbackServer.js +141 -0
- package/dist/src/auth/loopbackServer.js.map +1 -0
- package/dist/src/auth/token.d.ts +8 -0
- package/dist/src/auth/token.js +15 -0
- package/dist/src/auth/token.js.map +1 -0
- package/dist/src/commands/accountCommand.d.ts +2 -0
- package/dist/src/commands/accountCommand.js +56 -0
- package/dist/src/commands/accountCommand.js.map +1 -0
- package/dist/src/commands/configCommand.d.ts +4 -0
- package/dist/src/commands/configCommand.js +53 -0
- package/dist/src/commands/configCommand.js.map +1 -0
- package/dist/src/commands/execCommand.d.ts +32 -0
- package/dist/src/commands/execCommand.js +122 -0
- package/dist/src/commands/execCommand.js.map +1 -0
- package/dist/src/commands/loginCommand.d.ts +11 -0
- package/dist/src/commands/loginCommand.js +96 -0
- package/dist/src/commands/loginCommand.js.map +1 -0
- package/dist/src/commands/mediaCommand.d.ts +41 -0
- package/dist/src/commands/mediaCommand.js +277 -0
- package/dist/src/commands/mediaCommand.js.map +1 -0
- package/dist/src/config/configFile.d.ts +30 -0
- package/dist/src/config/configFile.js +54 -0
- package/dist/src/config/configFile.js.map +1 -0
- package/dist/src/config/env.d.ts +6 -0
- package/dist/src/config/env.js +24 -0
- package/dist/src/config/env.js.map +1 -0
- package/dist/src/config/paths.d.ts +6 -0
- package/dist/src/config/paths.js +16 -0
- package/dist/src/config/paths.js.map +1 -0
- package/dist/src/core/catalog.d.ts +49 -0
- package/dist/src/core/catalog.js +96 -0
- package/dist/src/core/catalog.js.map +1 -0
- package/dist/src/core/httpChatBackend.d.ts +31 -0
- package/dist/src/core/httpChatBackend.js +134 -0
- package/dist/src/core/httpChatBackend.js.map +1 -0
- package/dist/src/core/id.d.ts +2 -0
- package/dist/src/core/id.js +5 -0
- package/dist/src/core/id.js.map +1 -0
- package/dist/src/core/runChat.d.ts +28 -0
- package/dist/src/core/runChat.js +49 -0
- package/dist/src/core/runChat.js.map +1 -0
- package/dist/src/core/session.d.ts +44 -0
- package/dist/src/core/session.js +70 -0
- package/dist/src/core/session.js.map +1 -0
- package/dist/src/core/sessionStore.d.ts +39 -0
- package/dist/src/core/sessionStore.js +106 -0
- package/dist/src/core/sessionStore.js.map +1 -0
- package/dist/src/core/toolRegistry.d.ts +19 -0
- package/dist/src/core/toolRegistry.js +53 -0
- package/dist/src/core/toolRegistry.js.map +1 -0
- package/dist/src/core/tools/generateImage.d.ts +10 -0
- package/dist/src/core/tools/generateImage.js +34 -0
- package/dist/src/core/tools/generateImage.js.map +1 -0
- package/dist/src/core/turnLoop.d.ts +31 -0
- package/dist/src/core/turnLoop.js +155 -0
- package/dist/src/core/turnLoop.js.map +1 -0
- package/dist/src/core/types.d.ts +137 -0
- package/dist/src/core/types.js +9 -0
- package/dist/src/core/types.js.map +1 -0
- package/dist/src/exec/input.d.ts +35 -0
- package/dist/src/exec/input.js +85 -0
- package/dist/src/exec/input.js.map +1 -0
- package/dist/src/exec/output.d.ts +39 -0
- package/dist/src/exec/output.js +84 -0
- package/dist/src/exec/output.js.map +1 -0
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.js +253 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/mcp/server.d.ts +38 -0
- package/dist/src/mcp/server.js +99 -0
- package/dist/src/mcp/server.js.map +1 -0
- package/dist/src/media/aiApiClient.d.ts +53 -0
- package/dist/src/media/aiApiClient.js +97 -0
- package/dist/src/media/aiApiClient.js.map +1 -0
- package/dist/src/media/errors.d.ts +7 -0
- package/dist/src/media/errors.js +70 -0
- package/dist/src/media/errors.js.map +1 -0
- package/dist/src/media/executor.d.ts +50 -0
- package/dist/src/media/executor.js +55 -0
- package/dist/src/media/executor.js.map +1 -0
- package/dist/src/media/generateImageTool.d.ts +19 -0
- package/dist/src/media/generateImageTool.js +120 -0
- package/dist/src/media/generateImageTool.js.map +1 -0
- package/dist/src/media/manifest.d.ts +23 -0
- package/dist/src/media/manifest.js +558 -0
- package/dist/src/media/manifest.js.map +1 -0
- package/dist/src/media/resolution.d.ts +13 -0
- package/dist/src/media/resolution.js +42 -0
- package/dist/src/media/resolution.js.map +1 -0
- package/dist/src/media/taskLedger.d.ts +17 -0
- package/dist/src/media/taskLedger.js +44 -0
- package/dist/src/media/taskLedger.js.map +1 -0
- package/dist/src/media/taskManager.d.ts +52 -0
- package/dist/src/media/taskManager.js +130 -0
- package/dist/src/media/taskManager.js.map +1 -0
- package/dist/src/media/types.d.ts +80 -0
- package/dist/src/media/types.js +15 -0
- package/dist/src/media/types.js.map +1 -0
- package/dist/src/tui/App.d.ts +34 -0
- package/dist/src/tui/App.js +540 -0
- package/dist/src/tui/App.js.map +1 -0
- package/dist/src/tui/MultilineInput.d.ts +36 -0
- package/dist/src/tui/MultilineInput.js +221 -0
- package/dist/src/tui/MultilineInput.js.map +1 -0
- package/dist/src/tui/atPopup.d.ts +21 -0
- package/dist/src/tui/atPopup.js +55 -0
- package/dist/src/tui/atPopup.js.map +1 -0
- package/dist/src/tui/attachments.d.ts +24 -0
- package/dist/src/tui/attachments.js +91 -0
- package/dist/src/tui/attachments.js.map +1 -0
- package/dist/src/tui/branding.d.ts +22 -0
- package/dist/src/tui/branding.js +119 -0
- package/dist/src/tui/branding.js.map +1 -0
- package/dist/src/tui/chatController.d.ts +188 -0
- package/dist/src/tui/chatController.js +614 -0
- package/dist/src/tui/chatController.js.map +1 -0
- package/dist/src/tui/commands.d.ts +13 -0
- package/dist/src/tui/commands.js +22 -0
- package/dist/src/tui/commands.js.map +1 -0
- package/dist/src/tui/confirmationBridge.d.ts +23 -0
- package/dist/src/tui/confirmationBridge.js +47 -0
- package/dist/src/tui/confirmationBridge.js.map +1 -0
- package/dist/src/tui/inputHistory.d.ts +7 -0
- package/dist/src/tui/inputHistory.js +64 -0
- package/dist/src/tui/inputHistory.js.map +1 -0
- package/dist/src/tui/markdown.d.ts +1 -0
- package/dist/src/tui/markdown.js +143 -0
- package/dist/src/tui/markdown.js.map +1 -0
- package/dist/src/tui/models.d.ts +30 -0
- package/dist/src/tui/models.js +54 -0
- package/dist/src/tui/models.js.map +1 -0
- package/dist/src/tui/run.d.ts +29 -0
- package/dist/src/tui/run.js +212 -0
- package/dist/src/tui/run.js.map +1 -0
- package/dist/src/tui/slashMedia.d.ts +36 -0
- package/dist/src/tui/slashMedia.js +86 -0
- package/dist/src/tui/slashMedia.js.map +1 -0
- package/dist/src/tui/visualLines.d.ts +38 -0
- package/dist/src/tui/visualLines.js +110 -0
- package/dist/src/tui/visualLines.js.map +1 -0
- package/dist/src/util/clipboardImage.d.ts +6 -0
- package/dist/src/util/clipboardImage.js +69 -0
- package/dist/src/util/clipboardImage.js.map +1 -0
- package/dist/src/util/hyperlink.d.ts +10 -0
- package/dist/src/util/hyperlink.js +33 -0
- package/dist/src/util/hyperlink.js.map +1 -0
- package/dist/src/util/imageRef.d.ts +15 -0
- package/dist/src/util/imageRef.js +46 -0
- package/dist/src/util/imageRef.js.map +1 -0
- package/dist/src/util/inlineImage.d.ts +13 -0
- package/dist/src/util/inlineImage.js +56 -0
- package/dist/src/util/inlineImage.js.map +1 -0
- package/dist/src/util/openBrowser.d.ts +5 -0
- package/dist/src/util/openBrowser.js +23 -0
- package/dist/src/util/openBrowser.js.map +1 -0
- package/dist/src/util/retry.d.ts +43 -0
- package/dist/src/util/retry.js +116 -0
- package/dist/src/util/retry.js.map +1 -0
- package/dist/src/version.d.ts +6 -0
- package/dist/src/version.js +16 -0
- package/dist/src/version.js.map +1 -0
- package/package.json +45 -0
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { withRetry, isTransientNetworkError, describeNetworkError, hostOf } from '../util/retry.js';
|
|
2
|
+
/** Transient gateway/infra statuses worth retrying before the stream starts. */
|
|
3
|
+
const TRANSIENT_STATUS = new Set([502, 503, 504]);
|
|
4
|
+
/**
|
|
5
|
+
* Real chat backend: streams from `POST /ai-api/cli/v1/chat/completions` (OpenAI-compatible SSE).
|
|
6
|
+
*
|
|
7
|
+
* Note: the GlobalGPT gateway returns HTTP 200 for business errors with a JSON body
|
|
8
|
+
* (`{code, message}`) and Content-Type `application/json` instead of `text/event-stream`.
|
|
9
|
+
* We detect that by Content-Type and surface it as an error.
|
|
10
|
+
*/
|
|
11
|
+
export class HttpChatBackend {
|
|
12
|
+
baseUrl;
|
|
13
|
+
token;
|
|
14
|
+
fetchImpl;
|
|
15
|
+
retries;
|
|
16
|
+
sleep;
|
|
17
|
+
constructor(opts) {
|
|
18
|
+
this.baseUrl = opts.baseUrl.replace(/\/+$/, '');
|
|
19
|
+
this.token = opts.token;
|
|
20
|
+
this.fetchImpl = opts.fetchImpl ?? fetch;
|
|
21
|
+
this.retries = opts.retries ?? 3;
|
|
22
|
+
this.sleep = opts.sleep;
|
|
23
|
+
}
|
|
24
|
+
/** Hot-swap the JWT (used by the in-chat /login re-auth). */
|
|
25
|
+
setToken(token) {
|
|
26
|
+
this.token = token;
|
|
27
|
+
}
|
|
28
|
+
async *stream(req, signal) {
|
|
29
|
+
const url = `${this.baseUrl}/ai-api/cli/v1/chat/completions`;
|
|
30
|
+
const host = hostOf(this.baseUrl);
|
|
31
|
+
// Retry the request only up to (and including) receiving the response head. Once we begin
|
|
32
|
+
// reading the stream body below, we never retry — replaying a partially-billed stream would
|
|
33
|
+
// double-charge. Connection-level throws and transient 5xx are retried with backoff.
|
|
34
|
+
let res;
|
|
35
|
+
try {
|
|
36
|
+
res = await withRetry(() => this.fetchImpl(url, {
|
|
37
|
+
method: 'POST',
|
|
38
|
+
headers: {
|
|
39
|
+
'Content-Type': 'application/json',
|
|
40
|
+
Accept: 'text/event-stream',
|
|
41
|
+
Authorization: `Bearer ${this.token}`,
|
|
42
|
+
},
|
|
43
|
+
body: JSON.stringify(req),
|
|
44
|
+
signal,
|
|
45
|
+
}), {
|
|
46
|
+
retries: this.retries,
|
|
47
|
+
sleep: this.sleep,
|
|
48
|
+
isRetryableResult: (r) => TRANSIENT_STATUS.has(r.status),
|
|
49
|
+
// Never retry a user-initiated abort — it must interrupt immediately.
|
|
50
|
+
isRetryableError: (err) => !signal?.aborted && isTransientNetworkError(err),
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
54
|
+
// A user-initiated abort must propagate as-is (the turn loop treats it as an interrupt).
|
|
55
|
+
if (signal?.aborted)
|
|
56
|
+
throw err;
|
|
57
|
+
if (isTransientNetworkError(err)) {
|
|
58
|
+
throw new Error(describeNetworkError(err, host, this.retries));
|
|
59
|
+
}
|
|
60
|
+
throw err;
|
|
61
|
+
}
|
|
62
|
+
if (TRANSIENT_STATUS.has(res.status)) {
|
|
63
|
+
// Retries exhausted and the gateway is still unavailable.
|
|
64
|
+
throw new Error(describeNetworkError(new Error(`HTTP ${res.status}`), host, this.retries));
|
|
65
|
+
}
|
|
66
|
+
const contentType = res.headers.get('content-type') ?? '';
|
|
67
|
+
if (!contentType.includes('text/event-stream')) {
|
|
68
|
+
// Business error path: the gateway returns HTTP 200 + a JSON body with a `code`
|
|
69
|
+
// (401 expired/invalid, 402 payment) — never trust the HTTP status.
|
|
70
|
+
const text = await res.text();
|
|
71
|
+
let body = {};
|
|
72
|
+
try {
|
|
73
|
+
body = JSON.parse(text);
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
/* non-JSON */
|
|
77
|
+
}
|
|
78
|
+
throw businessError(body.code, body.message || text || `status ${res.status}`);
|
|
79
|
+
}
|
|
80
|
+
if (!res.body) {
|
|
81
|
+
throw new Error('Chat response has no body');
|
|
82
|
+
}
|
|
83
|
+
const decoder = new TextDecoder();
|
|
84
|
+
let buffer = '';
|
|
85
|
+
for await (const bytes of res.body) {
|
|
86
|
+
buffer += decoder.decode(bytes, { stream: true });
|
|
87
|
+
let idx;
|
|
88
|
+
while ((idx = buffer.indexOf('\n')) >= 0) {
|
|
89
|
+
const line = buffer.slice(0, idx).trim();
|
|
90
|
+
buffer = buffer.slice(idx + 1);
|
|
91
|
+
const chunk = parseSseLine(line);
|
|
92
|
+
if (chunk)
|
|
93
|
+
yield chunk;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
const tail = parseSseLine(buffer.trim());
|
|
97
|
+
if (tail)
|
|
98
|
+
yield tail;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/** Map a gateway business-error payload to an actionable Error. */
|
|
102
|
+
function businessError(code, message) {
|
|
103
|
+
if (code === 401)
|
|
104
|
+
return new Error('Your session has expired. Run `glbgpt login` again.');
|
|
105
|
+
if (code === 402)
|
|
106
|
+
return new Error(message || 'Payment required (insufficient balance or plan).');
|
|
107
|
+
return new Error(`Chat request failed: ${message}`);
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Parse one SSE line into a ChatChunk, or null for keepalives/[DONE]/non-data lines.
|
|
111
|
+
*
|
|
112
|
+
* The gateway can also reject WITHIN the stream: an `event: error` frame whose data is
|
|
113
|
+
* `{code, message}` with no `choices` (e.g. a model outside the backend whitelist). Silently
|
|
114
|
+
* ignoring it would make the turn complete with no output at all, so it throws instead.
|
|
115
|
+
*/
|
|
116
|
+
function parseSseLine(line) {
|
|
117
|
+
if (!line.startsWith('data:'))
|
|
118
|
+
return null;
|
|
119
|
+
const data = line.slice('data:'.length).trim();
|
|
120
|
+
if (!data || data === '[DONE]')
|
|
121
|
+
return null;
|
|
122
|
+
let parsed;
|
|
123
|
+
try {
|
|
124
|
+
parsed = JSON.parse(data);
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
if (parsed.choices === undefined && parsed.usage === undefined && typeof parsed.code === 'number') {
|
|
130
|
+
throw businessError(parsed.code, parsed.message ?? `code ${parsed.code}`);
|
|
131
|
+
}
|
|
132
|
+
return parsed;
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=httpChatBackend.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"httpChatBackend.js","sourceRoot":"","sources":["../../../src/core/httpChatBackend.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"id.js","sourceRoot":"","sources":["../../../src/core/id.ts"],"names":[],"mappings":"AAAA,0FAA0F;AAC1F,MAAM,UAAU,KAAK;IACnB,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC;AACtF,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { ChatBackend, ContentPart, EngineEvent } from './types.js';
|
|
2
|
+
/** One chat-only turn's result. `structured` is set when a response schema was requested. */
|
|
3
|
+
export interface ChatTurnResult {
|
|
4
|
+
content: string;
|
|
5
|
+
structured: unknown | null;
|
|
6
|
+
usage: {
|
|
7
|
+
prompt_tokens: number;
|
|
8
|
+
completion_tokens: number;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
export interface ChatTurnParams {
|
|
12
|
+
backend: ChatBackend;
|
|
13
|
+
model: string;
|
|
14
|
+
/** Plain text, or multimodal content parts (vision). */
|
|
15
|
+
prompt: string | ContentPart[];
|
|
16
|
+
system?: string;
|
|
17
|
+
/** OpenAI `response_format` value (json_schema) for structured output. */
|
|
18
|
+
responseFormat?: unknown;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Run a single chat-only turn (no client tools) and return the final message, parsed structured
|
|
22
|
+
* output (when a schema was requested), and token usage.
|
|
23
|
+
*
|
|
24
|
+
* Shared by `exec` and the MCP server so both behave identically. `onEvent` streams deltas/usage
|
|
25
|
+
* live (exec's --jsonl uses it); callers that only want the final result omit it. Throws on a
|
|
26
|
+
* backend/turn error or when structured output does not parse.
|
|
27
|
+
*/
|
|
28
|
+
export declare function runChatTurn(params: ChatTurnParams, onEvent?: (event: EngineEvent) => void): Promise<ChatTurnResult>;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Session } from './session.js';
|
|
2
|
+
import { TurnLoop } from './turnLoop.js';
|
|
3
|
+
import { ToolRegistry } from './toolRegistry.js';
|
|
4
|
+
import { newId } from './id.js';
|
|
5
|
+
/**
|
|
6
|
+
* Run a single chat-only turn (no client tools) and return the final message, parsed structured
|
|
7
|
+
* output (when a schema was requested), and token usage.
|
|
8
|
+
*
|
|
9
|
+
* Shared by `exec` and the MCP server so both behave identically. `onEvent` streams deltas/usage
|
|
10
|
+
* live (exec's --jsonl uses it); callers that only want the final result omit it. Throws on a
|
|
11
|
+
* backend/turn error or when structured output does not parse.
|
|
12
|
+
*/
|
|
13
|
+
export async function runChatTurn(params, onEvent) {
|
|
14
|
+
const session = new Session({ id: newId(), model: params.model });
|
|
15
|
+
if (params.system?.trim())
|
|
16
|
+
session.addSystemMessage(params.system.trim());
|
|
17
|
+
const turnLoop = new TurnLoop(params.backend, new ToolRegistry());
|
|
18
|
+
let content = '';
|
|
19
|
+
let usage = { prompt_tokens: 0, completion_tokens: 0 };
|
|
20
|
+
let engineError = null;
|
|
21
|
+
await turnLoop.runTurn(session, params.prompt, (event) => {
|
|
22
|
+
switch (event.type) {
|
|
23
|
+
case 'assistant_delta':
|
|
24
|
+
content += event.text;
|
|
25
|
+
break;
|
|
26
|
+
case 'usage':
|
|
27
|
+
usage = { prompt_tokens: event.promptTokens, completion_tokens: event.completionTokens };
|
|
28
|
+
break;
|
|
29
|
+
case 'error':
|
|
30
|
+
engineError = event.message;
|
|
31
|
+
break;
|
|
32
|
+
// tool_* never fire (no tools); turn_complete is implicit in runTurn resolving.
|
|
33
|
+
}
|
|
34
|
+
onEvent?.(event);
|
|
35
|
+
}, { responseFormat: params.responseFormat });
|
|
36
|
+
if (engineError)
|
|
37
|
+
throw new Error(engineError);
|
|
38
|
+
let structured = null;
|
|
39
|
+
if (params.responseFormat !== undefined) {
|
|
40
|
+
try {
|
|
41
|
+
structured = JSON.parse(content);
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
throw new Error('Model output did not parse as JSON despite the requested schema.');
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return { content, structured, usage };
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=runChat.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runChat.js","sourceRoot":"","sources":["../../../src/core/runChat.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAoBhC;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,MAAsB,EACtB,OAAsC;IAEtC,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;IAClE,IAAI,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE;QAAE,OAAO,CAAC,gBAAgB,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;IAC1E,MAAM,QAAQ,GAAG,IAAI,QAAQ,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,YAAY,EAAE,CAAC,CAAC;IAElE,IAAI,OAAO,GAAG,EAAE,CAAC;IACjB,IAAI,KAAK,GAAG,EAAE,aAAa,EAAE,CAAC,EAAE,iBAAiB,EAAE,CAAC,EAAE,CAAC;IACvD,IAAI,WAAW,GAAkB,IAAI,CAAC;IAEtC,MAAM,QAAQ,CAAC,OAAO,CACpB,OAAO,EACP,MAAM,CAAC,MAAM,EACb,CAAC,KAAK,EAAE,EAAE;QACR,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;YACnB,KAAK,iBAAiB;gBACpB,OAAO,IAAI,KAAK,CAAC,IAAI,CAAC;gBACtB,MAAM;YACR,KAAK,OAAO;gBACV,KAAK,GAAG,EAAE,aAAa,EAAE,KAAK,CAAC,YAAY,EAAE,iBAAiB,EAAE,KAAK,CAAC,gBAAgB,EAAE,CAAC;gBACzF,MAAM;YACR,KAAK,OAAO;gBACV,WAAW,GAAG,KAAK,CAAC,OAAO,CAAC;gBAC5B,MAAM;YACR,gFAAgF;QAClF,CAAC;QACD,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC;IACnB,CAAC,EACD,EAAE,cAAc,EAAE,MAAM,CAAC,cAAc,EAAE,CAC1C,CAAC;IAEF,IAAI,WAAW;QAAE,MAAM,IAAI,KAAK,CAAC,WAAW,CAAC,CAAC;IAE9C,IAAI,UAAU,GAAmB,IAAI,CAAC;IACtC,IAAI,MAAM,CAAC,cAAc,KAAK,SAAS,EAAE,CAAC;QACxC,IAAI,CAAC;YACH,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACnC,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,KAAK,CAAC,kEAAkE,CAAC,CAAC;QACtF,CAAC;IACH,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC;AACxC,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { ChatMessage, ToolCall, ToolResult } from './types.js';
|
|
2
|
+
/** Serializable snapshot of a conversation, used for local persistence and resume. */
|
|
3
|
+
export interface SessionSnapshot {
|
|
4
|
+
id: string;
|
|
5
|
+
model: string;
|
|
6
|
+
createdAt: number;
|
|
7
|
+
updatedAt: number;
|
|
8
|
+
messages: ChatMessage[];
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* A single conversation the CLI owns end to end.
|
|
12
|
+
*
|
|
13
|
+
* The CLI is a thin client: it carries the full `messages` array to the stateless
|
|
14
|
+
* backend each turn. Switching the model (`/model`) preserves the message history,
|
|
15
|
+
* so the new model continues the same conversation (product decision 2026-07-14).
|
|
16
|
+
*/
|
|
17
|
+
export declare class Session {
|
|
18
|
+
readonly id: string;
|
|
19
|
+
readonly createdAt: number;
|
|
20
|
+
model: string;
|
|
21
|
+
messages: ChatMessage[];
|
|
22
|
+
constructor(params: {
|
|
23
|
+
id: string;
|
|
24
|
+
model: string;
|
|
25
|
+
createdAt?: number;
|
|
26
|
+
messages?: ChatMessage[];
|
|
27
|
+
});
|
|
28
|
+
/** Prepend a system message (must precede the first user message to steer the model). */
|
|
29
|
+
addSystemMessage(text: string): void;
|
|
30
|
+
/**
|
|
31
|
+
* Append a system note mid-conversation (environment updates the model should know about,
|
|
32
|
+
* e.g. a background generation finishing after its tool call already returned).
|
|
33
|
+
*/
|
|
34
|
+
addSystemNote(text: string): void;
|
|
35
|
+
addUserMessage(content: string | import('./types.js').ContentPart[]): void;
|
|
36
|
+
/** Append the assistant message for a completed model call (text and/or tool_calls). */
|
|
37
|
+
addAssistantMessage(content: string | null, toolCalls: ToolCall[]): void;
|
|
38
|
+
/** Append a tool result message answering a specific tool call. */
|
|
39
|
+
addToolMessage(toolCallId: string, name: string, result: ToolResult): void;
|
|
40
|
+
/** Switch the active model while keeping the conversation history. */
|
|
41
|
+
switchModel(model: string): void;
|
|
42
|
+
toSnapshot(): SessionSnapshot;
|
|
43
|
+
static fromSnapshot(s: SessionSnapshot): Session;
|
|
44
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A single conversation the CLI owns end to end.
|
|
3
|
+
*
|
|
4
|
+
* The CLI is a thin client: it carries the full `messages` array to the stateless
|
|
5
|
+
* backend each turn. Switching the model (`/model`) preserves the message history,
|
|
6
|
+
* so the new model continues the same conversation (product decision 2026-07-14).
|
|
7
|
+
*/
|
|
8
|
+
export class Session {
|
|
9
|
+
id;
|
|
10
|
+
createdAt;
|
|
11
|
+
model;
|
|
12
|
+
messages;
|
|
13
|
+
constructor(params) {
|
|
14
|
+
this.id = params.id;
|
|
15
|
+
this.model = params.model;
|
|
16
|
+
this.createdAt = params.createdAt ?? nowMs();
|
|
17
|
+
this.messages = params.messages ?? [];
|
|
18
|
+
}
|
|
19
|
+
/** Prepend a system message (must precede the first user message to steer the model). */
|
|
20
|
+
addSystemMessage(text) {
|
|
21
|
+
this.messages.unshift({ role: 'system', content: text });
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Append a system note mid-conversation (environment updates the model should know about,
|
|
25
|
+
* e.g. a background generation finishing after its tool call already returned).
|
|
26
|
+
*/
|
|
27
|
+
addSystemNote(text) {
|
|
28
|
+
this.messages.push({ role: 'system', content: text });
|
|
29
|
+
}
|
|
30
|
+
addUserMessage(content) {
|
|
31
|
+
this.messages.push({ role: 'user', content });
|
|
32
|
+
}
|
|
33
|
+
/** Append the assistant message for a completed model call (text and/or tool_calls). */
|
|
34
|
+
addAssistantMessage(content, toolCalls) {
|
|
35
|
+
const msg = { role: 'assistant', content: content ?? null };
|
|
36
|
+
if (toolCalls.length > 0) {
|
|
37
|
+
msg.tool_calls = toolCalls;
|
|
38
|
+
}
|
|
39
|
+
this.messages.push(msg);
|
|
40
|
+
}
|
|
41
|
+
/** Append a tool result message answering a specific tool call. */
|
|
42
|
+
addToolMessage(toolCallId, name, result) {
|
|
43
|
+
this.messages.push({
|
|
44
|
+
role: 'tool',
|
|
45
|
+
tool_call_id: toolCallId,
|
|
46
|
+
name,
|
|
47
|
+
content: JSON.stringify(result),
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
/** Switch the active model while keeping the conversation history. */
|
|
51
|
+
switchModel(model) {
|
|
52
|
+
this.model = model;
|
|
53
|
+
}
|
|
54
|
+
toSnapshot() {
|
|
55
|
+
return {
|
|
56
|
+
id: this.id,
|
|
57
|
+
model: this.model,
|
|
58
|
+
createdAt: this.createdAt,
|
|
59
|
+
updatedAt: nowMs(),
|
|
60
|
+
messages: this.messages,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
static fromSnapshot(s) {
|
|
64
|
+
return new Session({ id: s.id, model: s.model, createdAt: s.createdAt, messages: s.messages });
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function nowMs() {
|
|
68
|
+
return Date.now();
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../../src/core/session.ts"],"names":[],"mappings":"AAWA;;;;;;GAMG;AACH,MAAM,OAAO,OAAO;IACT,EAAE,CAAS;IACX,SAAS,CAAS;IAC3B,KAAK,CAAS;IACd,QAAQ,CAAgB;IAExB,YAAY,MAAmF;QAC7F,IAAI,CAAC,EAAE,GAAG,MAAM,CAAC,EAAE,CAAC;QACpB,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;QAC1B,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,IAAI,KAAK,EAAE,CAAC;QAC7C,IAAI,CAAC,QAAQ,GAAG,MAAM,CAAC,QAAQ,IAAI,EAAE,CAAC;IACxC,CAAC;IAED,yFAAyF;IACzF,gBAAgB,CAAC,IAAY;QAC3B,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3D,CAAC;IAED;;;OAGG;IACH,aAAa,CAAC,IAAY;QACxB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;IACxD,CAAC;IAED,cAAc,CAAC,OAAoD;QACjE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;IAChD,CAAC;IAED,wFAAwF;IACxF,mBAAmB,CAAC,OAAsB,EAAE,SAAqB;QAC/D,MAAM,GAAG,GAAgB,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,CAAC;QACzE,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACzB,GAAG,CAAC,UAAU,GAAG,SAAS,CAAC;QAC7B,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC1B,CAAC;IAED,mEAAmE;IACnE,cAAc,CAAC,UAAkB,EAAE,IAAY,EAAE,MAAkB;QACjE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;YACjB,IAAI,EAAE,MAAM;YACZ,YAAY,EAAE,UAAU;YACxB,IAAI;YACJ,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC;SAChC,CAAC,CAAC;IACL,CAAC;IAED,sEAAsE;IACtE,WAAW,CAAC,KAAa;QACvB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACrB,CAAC;IAED,UAAU;QACR,OAAO;YACL,EAAE,EAAE,IAAI,CAAC,EAAE;YACX,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,SAAS,EAAE,KAAK,EAAE;YAClB,QAAQ,EAAE,IAAI,CAAC,QAAQ;SACxB,CAAC;IACJ,CAAC;IAED,MAAM,CAAC,YAAY,CAAC,CAAkB;QACpC,OAAO,IAAI,OAAO,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;IACjG,CAAC;CACF;AAED,SAAS,KAAK;IACZ,OAAO,IAAI,CAAC,GAAG,EAAE,CAAC;AACpB,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Session } from './session.js';
|
|
2
|
+
/**
|
|
3
|
+
* A persisted UI transcript entry. Stored ALONGSIDE the model messages (the Codex
|
|
4
|
+
* rollout / Claude Code transcript architecture: model context and UI events are
|
|
5
|
+
* separate, parallel records) — the TUI owns the concrete shape.
|
|
6
|
+
*/
|
|
7
|
+
export type PersistedTimelineItem = Record<string, unknown>;
|
|
8
|
+
/** One row in the `/resume` session picker. */
|
|
9
|
+
export interface SessionSummary {
|
|
10
|
+
id: string;
|
|
11
|
+
model: string;
|
|
12
|
+
updatedAt: number;
|
|
13
|
+
/** First user message, truncated — enough to recognize the conversation. */
|
|
14
|
+
preview: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Local persistence for sessions (phase 1: one JSON file per session under a directory).
|
|
18
|
+
*
|
|
19
|
+
* Phase-1 scope: history lives on the client only. A future phase may sync sessions to
|
|
20
|
+
* the backend; the store interface stays the same.
|
|
21
|
+
*/
|
|
22
|
+
export declare class SessionStore {
|
|
23
|
+
private readonly dir;
|
|
24
|
+
/** Serializes writes — two subscribers (task events + turn settle) can save concurrently. */
|
|
25
|
+
private writeChain;
|
|
26
|
+
constructor(dir: string);
|
|
27
|
+
private file;
|
|
28
|
+
save(session: Session, timeline?: PersistedTimelineItem[]): Promise<void>;
|
|
29
|
+
load(id: string): Promise<Session>;
|
|
30
|
+
/** Load a session plus its persisted transcript (absent in pre-2026-07-15 files). */
|
|
31
|
+
loadWithTimeline(id: string): Promise<{
|
|
32
|
+
session: Session;
|
|
33
|
+
timeline?: PersistedTimelineItem[];
|
|
34
|
+
}>;
|
|
35
|
+
/** Summaries of stored sessions, newest first (for the `/resume` picker). */
|
|
36
|
+
list(limit?: number): Promise<SessionSummary[]>;
|
|
37
|
+
/** Resume the most recently updated session, or null if none exist. */
|
|
38
|
+
loadLast(): Promise<Session | null>;
|
|
39
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { promises as fs } from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { Session } from './session.js';
|
|
4
|
+
/**
|
|
5
|
+
* Local persistence for sessions (phase 1: one JSON file per session under a directory).
|
|
6
|
+
*
|
|
7
|
+
* Phase-1 scope: history lives on the client only. A future phase may sync sessions to
|
|
8
|
+
* the backend; the store interface stays the same.
|
|
9
|
+
*/
|
|
10
|
+
export class SessionStore {
|
|
11
|
+
dir;
|
|
12
|
+
/** Serializes writes — two subscribers (task events + turn settle) can save concurrently. */
|
|
13
|
+
writeChain = Promise.resolve();
|
|
14
|
+
constructor(dir) {
|
|
15
|
+
this.dir = dir;
|
|
16
|
+
}
|
|
17
|
+
file(id) {
|
|
18
|
+
return path.join(this.dir, `${id}.json`);
|
|
19
|
+
}
|
|
20
|
+
async save(session, timeline) {
|
|
21
|
+
// Snapshot NOW (caller-time state), write in order. tmp+rename keeps the file readable
|
|
22
|
+
// even if the process dies mid-write (the Codex rollout recorder's durability property —
|
|
23
|
+
// a torn session file is unrecoverable, not just missing its tail).
|
|
24
|
+
const snapshot = { ...session.toSnapshot(), ...(timeline ? { timeline } : {}) };
|
|
25
|
+
const file = this.file(session.id);
|
|
26
|
+
this.writeChain = this.writeChain.then(async () => {
|
|
27
|
+
await fs.mkdir(this.dir, { recursive: true });
|
|
28
|
+
const tmp = `${file}.${process.pid}.tmp`;
|
|
29
|
+
await fs.writeFile(tmp, JSON.stringify(snapshot, null, 2), 'utf8');
|
|
30
|
+
await fs.rename(tmp, file);
|
|
31
|
+
});
|
|
32
|
+
await this.writeChain;
|
|
33
|
+
}
|
|
34
|
+
async load(id) {
|
|
35
|
+
return (await this.loadWithTimeline(id)).session;
|
|
36
|
+
}
|
|
37
|
+
/** Load a session plus its persisted transcript (absent in pre-2026-07-15 files). */
|
|
38
|
+
async loadWithTimeline(id) {
|
|
39
|
+
const raw = await fs.readFile(this.file(id), 'utf8');
|
|
40
|
+
const snapshot = JSON.parse(raw);
|
|
41
|
+
return { session: Session.fromSnapshot(snapshot), timeline: snapshot.timeline };
|
|
42
|
+
}
|
|
43
|
+
/** Summaries of stored sessions, newest first (for the `/resume` picker). */
|
|
44
|
+
async list(limit = 10) {
|
|
45
|
+
let entries;
|
|
46
|
+
try {
|
|
47
|
+
entries = await fs.readdir(this.dir);
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return [];
|
|
51
|
+
}
|
|
52
|
+
const summaries = [];
|
|
53
|
+
for (const file of entries.filter((e) => e.endsWith('.json'))) {
|
|
54
|
+
try {
|
|
55
|
+
const raw = await fs.readFile(path.join(this.dir, file), 'utf8');
|
|
56
|
+
const snap = JSON.parse(raw);
|
|
57
|
+
const firstUser = snap.messages.find((m) => m.role === 'user');
|
|
58
|
+
const raw0 = firstUser?.content;
|
|
59
|
+
// Multimodal user messages store content parts; preview the text part.
|
|
60
|
+
const previewText = typeof raw0 === 'string'
|
|
61
|
+
? raw0
|
|
62
|
+
: Array.isArray(raw0)
|
|
63
|
+
? raw0.map((p) => (p.type === 'text' ? p.text : '')).join('')
|
|
64
|
+
: '(empty)';
|
|
65
|
+
summaries.push({
|
|
66
|
+
id: snap.id,
|
|
67
|
+
model: snap.model,
|
|
68
|
+
updatedAt: snap.updatedAt,
|
|
69
|
+
preview: (previewText || '(empty)').slice(0, 60),
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
// Skip unreadable/corrupt files.
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return summaries.sort((a, b) => b.updatedAt - a.updatedAt).slice(0, limit);
|
|
77
|
+
}
|
|
78
|
+
/** Resume the most recently updated session, or null if none exist. */
|
|
79
|
+
async loadLast() {
|
|
80
|
+
let entries;
|
|
81
|
+
try {
|
|
82
|
+
entries = await fs.readdir(this.dir);
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
const jsonFiles = entries.filter((e) => e.endsWith('.json'));
|
|
88
|
+
if (jsonFiles.length === 0)
|
|
89
|
+
return null;
|
|
90
|
+
let newest = null;
|
|
91
|
+
for (const file of jsonFiles) {
|
|
92
|
+
try {
|
|
93
|
+
const raw = await fs.readFile(path.join(this.dir, file), 'utf8');
|
|
94
|
+
const snap = JSON.parse(raw);
|
|
95
|
+
if (!newest || snap.updatedAt > newest.updatedAt) {
|
|
96
|
+
newest = { id: snap.id, updatedAt: snap.updatedAt };
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
// Skip unreadable/corrupt files.
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return newest ? this.load(newest.id) : null;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=sessionStore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sessionStore.js","sourceRoot":"","sources":["../../../src/core/sessionStore.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ClientTool, OpenAITool, ToolResult } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Registry of client-side tools the model may call.
|
|
4
|
+
*
|
|
5
|
+
* Tools execute locally in the CLI (they are NOT backend concerns). The registry
|
|
6
|
+
* exposes their OpenAI definitions for the request and dispatches calls by name.
|
|
7
|
+
*/
|
|
8
|
+
export declare class ToolRegistry {
|
|
9
|
+
private readonly tools;
|
|
10
|
+
register(tool: ClientTool): this;
|
|
11
|
+
has(name: string): boolean;
|
|
12
|
+
/** OpenAI `tools` array for the chat request. Undefined when no tools are registered. */
|
|
13
|
+
toOpenAITools(): OpenAITool[] | undefined;
|
|
14
|
+
/**
|
|
15
|
+
* Dispatch a tool call. `rawArgs` is the JSON-encoded arguments string the model produced.
|
|
16
|
+
* Never throws: parse/execution failures are returned as an error result so the model can react.
|
|
17
|
+
*/
|
|
18
|
+
dispatch(name: string, rawArgs: string): Promise<ToolResult>;
|
|
19
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registry of client-side tools the model may call.
|
|
3
|
+
*
|
|
4
|
+
* Tools execute locally in the CLI (they are NOT backend concerns). The registry
|
|
5
|
+
* exposes their OpenAI definitions for the request and dispatches calls by name.
|
|
6
|
+
*/
|
|
7
|
+
export class ToolRegistry {
|
|
8
|
+
tools = new Map();
|
|
9
|
+
register(tool) {
|
|
10
|
+
this.tools.set(tool.name, tool);
|
|
11
|
+
return this;
|
|
12
|
+
}
|
|
13
|
+
has(name) {
|
|
14
|
+
return this.tools.has(name);
|
|
15
|
+
}
|
|
16
|
+
/** OpenAI `tools` array for the chat request. Undefined when no tools are registered. */
|
|
17
|
+
toOpenAITools() {
|
|
18
|
+
if (this.tools.size === 0)
|
|
19
|
+
return undefined;
|
|
20
|
+
return [...this.tools.values()].map((t) => ({
|
|
21
|
+
type: 'function',
|
|
22
|
+
function: {
|
|
23
|
+
name: t.name,
|
|
24
|
+
description: t.description,
|
|
25
|
+
parameters: t.parameters,
|
|
26
|
+
},
|
|
27
|
+
}));
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Dispatch a tool call. `rawArgs` is the JSON-encoded arguments string the model produced.
|
|
31
|
+
* Never throws: parse/execution failures are returned as an error result so the model can react.
|
|
32
|
+
*/
|
|
33
|
+
async dispatch(name, rawArgs) {
|
|
34
|
+
const tool = this.tools.get(name);
|
|
35
|
+
if (!tool) {
|
|
36
|
+
return { error: `Unknown tool: ${name}` };
|
|
37
|
+
}
|
|
38
|
+
let args;
|
|
39
|
+
try {
|
|
40
|
+
args = rawArgs && rawArgs.trim() ? JSON.parse(rawArgs) : {};
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return { error: `Invalid tool arguments (not valid JSON): ${rawArgs}` };
|
|
44
|
+
}
|
|
45
|
+
try {
|
|
46
|
+
return await tool.execute(args);
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
return { error: err instanceof Error ? err.message : String(err) };
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=toolRegistry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toolRegistry.js","sourceRoot":"","sources":["../../../src/core/toolRegistry.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,MAAM,OAAO,YAAY;IACN,KAAK,GAAG,IAAI,GAAG,EAAsB,CAAC;IAEvD,QAAQ,CAAC,IAAgB;QACvB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAChC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,GAAG,CAAC,IAAY;QACd,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC9B,CAAC;IAED,yFAAyF;IACzF,aAAa;QACX,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC;YAAE,OAAO,SAAS,CAAC;QAC5C,OAAO,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC1C,IAAI,EAAE,UAAmB;YACzB,QAAQ,EAAE;gBACR,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,WAAW,EAAE,CAAC,CAAC,WAAW;gBAC1B,UAAU,EAAE,CAAC,CAAC,UAAU;aACzB;SACF,CAAC,CAAC,CAAC;IACN,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,QAAQ,CAAC,IAAY,EAAE,OAAe;QAC1C,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAClC,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAO,EAAE,KAAK,EAAE,iBAAiB,IAAI,EAAE,EAAE,CAAC;QAC5C,CAAC;QACD,IAAI,IAA6B,CAAC;QAClC,IAAI,CAAC;YACH,IAAI,GAAG,OAAO,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9D,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,KAAK,EAAE,4CAA4C,OAAO,EAAE,EAAE,CAAC;QAC1E,CAAC;QACD,IAAI,CAAC;YACH,OAAO,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAClC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,EAAE,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;QACrE,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ClientTool } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Phase-1 STUB image generation tool.
|
|
4
|
+
*
|
|
5
|
+
* In phase 1 this returns a fake task id and does NOT call the real generation
|
|
6
|
+
* endpoint or incur any media billing (per the vertical-slice scope). A later phase
|
|
7
|
+
* wires `execute` to the real `POST /ai-api/ai/{model}/task/submit` flow and the CLI
|
|
8
|
+
* task-management commands take over waiting/downloading.
|
|
9
|
+
*/
|
|
10
|
+
export declare function createStubGenerateImageTool(): ClientTool;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase-1 STUB image generation tool.
|
|
3
|
+
*
|
|
4
|
+
* In phase 1 this returns a fake task id and does NOT call the real generation
|
|
5
|
+
* endpoint or incur any media billing (per the vertical-slice scope). A later phase
|
|
6
|
+
* wires `execute` to the real `POST /ai-api/ai/{model}/task/submit` flow and the CLI
|
|
7
|
+
* task-management commands take over waiting/downloading.
|
|
8
|
+
*/
|
|
9
|
+
export function createStubGenerateImageTool() {
|
|
10
|
+
let counter = 0;
|
|
11
|
+
return {
|
|
12
|
+
name: 'generate_image',
|
|
13
|
+
description: 'Generate an image from a text prompt. Returns a task id; the image runs in the background.',
|
|
14
|
+
parameters: {
|
|
15
|
+
type: 'object',
|
|
16
|
+
properties: {
|
|
17
|
+
prompt: { type: 'string', description: 'What to generate' },
|
|
18
|
+
aspect_ratio: { type: 'string', description: 'e.g. 1:1, 16:9, 9:16' },
|
|
19
|
+
},
|
|
20
|
+
required: ['prompt'],
|
|
21
|
+
},
|
|
22
|
+
async execute(args) {
|
|
23
|
+
counter += 1;
|
|
24
|
+
const taskId = `stub-image-${counter}`;
|
|
25
|
+
return {
|
|
26
|
+
task_id: taskId,
|
|
27
|
+
status: 'submitted',
|
|
28
|
+
stub: true,
|
|
29
|
+
prompt: typeof args.prompt === 'string' ? args.prompt : '',
|
|
30
|
+
};
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=generateImage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generateImage.js","sourceRoot":"","sources":["../../../../src/core/tools/generateImage.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AACH,MAAM,UAAU,2BAA2B;IACzC,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,OAAO;QACL,IAAI,EAAE,gBAAgB;QACtB,WAAW,EACT,4FAA4F;QAC9F,UAAU,EAAE;YACV,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,kBAAkB,EAAE;gBAC3D,YAAY,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,sBAAsB,EAAE;aACtE;YACD,QAAQ,EAAE,CAAC,QAAQ,CAAC;SACrB;QACD,KAAK,CAAC,OAAO,CAAC,IAA6B;YACzC,OAAO,IAAI,CAAC,CAAC;YACb,MAAM,MAAM,GAAG,cAAc,OAAO,EAAE,CAAC;YACvC,OAAO;gBACL,OAAO,EAAE,MAAM;gBACf,MAAM,EAAE,WAAW;gBACnB,IAAI,EAAE,IAAI;gBACV,MAAM,EAAE,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;aAC3D,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC"}
|