@agent-api/app-engine 0.0.2 → 0.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.d.ts +1 -1
- package/dist/agent.js +1 -1
- package/dist/config.d.ts +4 -0
- package/dist/config.js +33 -1
- package/dist/conversation/index.d.ts +2 -0
- package/dist/conversation/index.js +42 -3
- package/dist/engine/agent-engine.d.ts +1 -0
- package/dist/engine/agent-engine.js +32 -0
- package/dist/engine/index.d.ts +1 -1
- package/dist/engine/index.js +1 -1
- package/dist/workbench/command-controller.js +17 -5
- package/dist/workbench/conversation-controller.d.ts +13 -9
- package/dist/workbench/conversation-controller.js +27 -12
- package/dist/workbench/render-model.d.ts +3 -0
- package/dist/workbench/render-model.js +3 -0
- package/dist/workbench/state.d.ts +6 -0
- package/dist/workbench/state.js +11 -1
- package/package.json +1 -1
package/dist/agent.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { type AgentRunOptions, type AgentTurnEvent, type AgentTurnResult, type LocalToolApprovalRequest, type WorkdirAccessMode, agentResponseFailureMessage, agentTurnEventFromStreamEvent, clearPresetToolCatalogCache, isAvailablePreset, listAvailablePresets, resolveAgentRequestTools, resumeAgentAfterLocalApproval, runAgent, runAgentTurn, } from "./agent/runner.js";
|
|
2
|
-
export { conversationSummary, deleteConversation, getConversation, listConversations, } from "./conversation/index.js";
|
|
2
|
+
export { conversationSummary, deleteConversation, ensureConversation, getConversation, listConversations, startFreshConversation, } from "./conversation/index.js";
|
package/dist/agent.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { agentResponseFailureMessage, agentTurnEventFromStreamEvent, clearPresetToolCatalogCache, isAvailablePreset, listAvailablePresets, resolveAgentRequestTools, resumeAgentAfterLocalApproval, runAgent, runAgentTurn, } from "./agent/runner.js";
|
|
2
|
-
export { conversationSummary, deleteConversation, getConversation, listConversations, } from "./conversation/index.js";
|
|
2
|
+
export { conversationSummary, deleteConversation, ensureConversation, getConversation, listConversations, startFreshConversation, } from "./conversation/index.js";
|
package/dist/config.d.ts
CHANGED
|
@@ -25,9 +25,11 @@ export interface CLIConfig {
|
|
|
25
25
|
profiles: Record<string, Profile>;
|
|
26
26
|
}
|
|
27
27
|
export interface ConversationState {
|
|
28
|
+
id: string;
|
|
28
29
|
name: string;
|
|
29
30
|
profile: string;
|
|
30
31
|
previousResponseId?: string;
|
|
32
|
+
createdAt: number;
|
|
31
33
|
updatedAt: number;
|
|
32
34
|
}
|
|
33
35
|
export interface WorkbenchPreferences {
|
|
@@ -51,6 +53,8 @@ export declare function activeProfile(profileName?: string): Promise<Profile>;
|
|
|
51
53
|
export declare function emptyConfig(): CLIConfig;
|
|
52
54
|
export declare function emptyAppConfiguration(): AppConfiguration;
|
|
53
55
|
export declare function emptyConversationConfiguration(): ConversationConfiguration;
|
|
56
|
+
export declare function createConversationID(): string;
|
|
57
|
+
export declare function legacyConversationID(profile: string, name: string): string;
|
|
54
58
|
export declare function loadWorkbenchPreferences(): Promise<WorkbenchPreferences>;
|
|
55
59
|
export declare function updateWorkbenchPreferences(patch: {
|
|
56
60
|
defaultPreset?: string | null | undefined;
|
package/dist/config.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
2
3
|
import { ensureRuntime, runtime } from "./runtime/index.js";
|
|
3
4
|
export const defaultBaseURL = "https://api.agentsway.dev";
|
|
4
5
|
export const configFile = "profiles.json";
|
|
@@ -25,9 +26,11 @@ const profileSchema = z.object({
|
|
|
25
26
|
updatedAt: z.number(),
|
|
26
27
|
});
|
|
27
28
|
const conversationSchema = z.object({
|
|
29
|
+
id: z.string().optional(),
|
|
28
30
|
name: z.string(),
|
|
29
31
|
profile: z.string(),
|
|
30
32
|
previousResponseId: z.string().optional(),
|
|
33
|
+
createdAt: z.number().optional(),
|
|
31
34
|
updatedAt: z.number(),
|
|
32
35
|
});
|
|
33
36
|
const workbenchPreferencesSchema = z.object({
|
|
@@ -88,7 +91,11 @@ export async function loadConversationConfiguration() {
|
|
|
88
91
|
if (!parsed.success) {
|
|
89
92
|
throw new Error(`Invalid conversation configuration: ${parsed.error.issues.map((issue) => issue.message).join("; ")}`);
|
|
90
93
|
}
|
|
91
|
-
|
|
94
|
+
const normalized = normalizeConversationConfiguration(parsed.data);
|
|
95
|
+
if (normalized.changed) {
|
|
96
|
+
await saveConversationConfiguration(normalized.config);
|
|
97
|
+
}
|
|
98
|
+
return normalized.config;
|
|
92
99
|
}
|
|
93
100
|
export async function saveConversationConfiguration(config) {
|
|
94
101
|
await ensureRuntime();
|
|
@@ -126,6 +133,31 @@ export function emptyAppConfiguration() {
|
|
|
126
133
|
export function emptyConversationConfiguration() {
|
|
127
134
|
return { conversations: {} };
|
|
128
135
|
}
|
|
136
|
+
export function createConversationID() {
|
|
137
|
+
return `conv_${randomUUID().replace(/-/g, "").slice(0, 24)}`;
|
|
138
|
+
}
|
|
139
|
+
export function legacyConversationID(profile, name) {
|
|
140
|
+
return `conv_${createHash("sha256").update(`${profile}:${name}`).digest("hex").slice(0, 24)}`;
|
|
141
|
+
}
|
|
142
|
+
function normalizeConversationConfiguration(config) {
|
|
143
|
+
let changed = false;
|
|
144
|
+
const conversations = {};
|
|
145
|
+
for (const [key, conversation] of Object.entries(config.conversations)) {
|
|
146
|
+
const id = conversation.id || legacyConversationID(conversation.profile, conversation.name);
|
|
147
|
+
const createdAt = conversation.createdAt ?? conversation.updatedAt;
|
|
148
|
+
if (!conversation.id || !conversation.createdAt)
|
|
149
|
+
changed = true;
|
|
150
|
+
conversations[key] = {
|
|
151
|
+
id,
|
|
152
|
+
name: conversation.name,
|
|
153
|
+
profile: conversation.profile,
|
|
154
|
+
previousResponseId: conversation.previousResponseId,
|
|
155
|
+
createdAt,
|
|
156
|
+
updatedAt: conversation.updatedAt,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
return { config: { conversations }, changed };
|
|
160
|
+
}
|
|
129
161
|
export async function loadWorkbenchPreferences() {
|
|
130
162
|
const appConfig = await loadAppConfiguration();
|
|
131
163
|
return appConfig.workbench;
|
|
@@ -11,6 +11,8 @@ export declare function updateConversation(options: {
|
|
|
11
11
|
profile?: string;
|
|
12
12
|
conversation?: string;
|
|
13
13
|
}, responseID: string): Promise<void>;
|
|
14
|
+
export declare function ensureConversation(name: string, profileName?: string): Promise<ConversationState>;
|
|
15
|
+
export declare function startFreshConversation(name: string, profileName?: string): Promise<ConversationState>;
|
|
14
16
|
export declare function listConversations(profileName?: string): Promise<ConversationState[]>;
|
|
15
17
|
export declare function getConversation(name: string, profileName?: string): Promise<ConversationState>;
|
|
16
18
|
export declare function deleteConversation(name: string, profileName?: string): Promise<void>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { activeProfile, loadConversationConfiguration, saveConversationConfiguration } from "../config.js";
|
|
1
|
+
import { activeProfile, createConversationID, loadConversationConfiguration, saveConversationConfiguration, } from "../config.js";
|
|
2
2
|
export function conversationKey(profile, name) {
|
|
3
3
|
return `${profile}:${name}`;
|
|
4
4
|
}
|
|
@@ -18,14 +18,53 @@ export async function updateConversation(options, responseID) {
|
|
|
18
18
|
return;
|
|
19
19
|
const profile = await activeProfile(options.profile);
|
|
20
20
|
const config = await loadConversationConfiguration();
|
|
21
|
+
const key = conversationKey(profile.name, options.conversation);
|
|
22
|
+
const existing = config.conversations[key];
|
|
23
|
+
const now = Math.floor(Date.now() / 1000);
|
|
21
24
|
config.conversations[conversationKey(profile.name, options.conversation)] = {
|
|
25
|
+
id: existing?.id ?? createConversationID(),
|
|
22
26
|
name: options.conversation,
|
|
23
27
|
profile: profile.name,
|
|
24
28
|
previousResponseId: responseID,
|
|
25
|
-
|
|
29
|
+
createdAt: existing?.createdAt ?? now,
|
|
30
|
+
updatedAt: now,
|
|
26
31
|
};
|
|
27
32
|
await saveConversationConfiguration(config);
|
|
28
33
|
}
|
|
34
|
+
export async function ensureConversation(name, profileName) {
|
|
35
|
+
const profile = await activeProfile(profileName);
|
|
36
|
+
const config = await loadConversationConfiguration();
|
|
37
|
+
const key = conversationKey(profile.name, name);
|
|
38
|
+
const existing = config.conversations[key];
|
|
39
|
+
if (existing)
|
|
40
|
+
return existing;
|
|
41
|
+
const now = Math.floor(Date.now() / 1000);
|
|
42
|
+
const conversation = {
|
|
43
|
+
id: createConversationID(),
|
|
44
|
+
name,
|
|
45
|
+
profile: profile.name,
|
|
46
|
+
createdAt: now,
|
|
47
|
+
updatedAt: now,
|
|
48
|
+
};
|
|
49
|
+
config.conversations[key] = conversation;
|
|
50
|
+
await saveConversationConfiguration(config);
|
|
51
|
+
return conversation;
|
|
52
|
+
}
|
|
53
|
+
export async function startFreshConversation(name, profileName) {
|
|
54
|
+
const profile = await activeProfile(profileName);
|
|
55
|
+
const config = await loadConversationConfiguration();
|
|
56
|
+
const now = Math.floor(Date.now() / 1000);
|
|
57
|
+
const conversation = {
|
|
58
|
+
id: createConversationID(),
|
|
59
|
+
name,
|
|
60
|
+
profile: profile.name,
|
|
61
|
+
createdAt: now,
|
|
62
|
+
updatedAt: now,
|
|
63
|
+
};
|
|
64
|
+
config.conversations[conversationKey(profile.name, name)] = conversation;
|
|
65
|
+
await saveConversationConfiguration(config);
|
|
66
|
+
return conversation;
|
|
67
|
+
}
|
|
29
68
|
export async function listConversations(profileName) {
|
|
30
69
|
const profile = await activeProfile(profileName);
|
|
31
70
|
const config = await loadConversationConfiguration();
|
|
@@ -50,5 +89,5 @@ export async function deleteConversation(name, profileName) {
|
|
|
50
89
|
export function conversationSummary(conversation) {
|
|
51
90
|
const updated = new Date(conversation.updatedAt * 1000).toISOString();
|
|
52
91
|
const response = conversation.previousResponseId ? ` response=${conversation.previousResponseId}` : "";
|
|
53
|
-
return `${conversation.name}\t${conversation.profile}\t${updated}${response}`;
|
|
92
|
+
return `${conversation.name}\t${conversation.profile}\t${updated}\t${conversation.id}${response}`;
|
|
54
93
|
}
|
|
@@ -12,6 +12,7 @@ export interface AgentEngineApp {
|
|
|
12
12
|
subscribe(listener: () => void): () => void;
|
|
13
13
|
dispatch(action: WorkbenchAction): void;
|
|
14
14
|
maybeCheckForUpdate(options?: AgentEngineLifecycleOptions): Promise<void>;
|
|
15
|
+
loadInitialConversation(options?: AgentEngineLifecycleOptions): Promise<void>;
|
|
15
16
|
loadInitialSettings(options?: AgentEngineLifecycleOptions): Promise<void>;
|
|
16
17
|
loadWorkdir(path?: string, options?: AgentEngineLifecycleOptions): Promise<void>;
|
|
17
18
|
refreshAuth(profile?: string, options?: AgentEngineLifecycleOptions): Promise<void>;
|
|
@@ -35,6 +35,37 @@ export function createAgentEngine(options) {
|
|
|
35
35
|
const effects = await session.lifecycle.maybeCheckForUpdate();
|
|
36
36
|
runLifecycleEffects(effects, lifecycleOptions);
|
|
37
37
|
}
|
|
38
|
+
async function loadInitialConversation(lifecycleOptions = {}) {
|
|
39
|
+
try {
|
|
40
|
+
const state = session.engine.snapshot();
|
|
41
|
+
const conversation = await session.conversation.resolveConversation(state.currentConversation, options.baseOptions.profile);
|
|
42
|
+
if (lifecycleOptions.isMounted && !lifecycleOptions.isMounted())
|
|
43
|
+
return;
|
|
44
|
+
session.engine.dispatch({
|
|
45
|
+
type: "conversation.set",
|
|
46
|
+
id: conversation.id,
|
|
47
|
+
name: conversation.name,
|
|
48
|
+
previousResponseId: conversation.previousResponseId,
|
|
49
|
+
status: conversation.status,
|
|
50
|
+
});
|
|
51
|
+
if (conversation.previousResponseId) {
|
|
52
|
+
session.engine.dispatch({
|
|
53
|
+
type: "message.add",
|
|
54
|
+
role: "system",
|
|
55
|
+
text: `Continuing conversation "${conversation.name}" from ${conversation.previousResponseId}. Use /new to start without prior context.`,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
if (lifecycleOptions.isMounted && !lifecycleOptions.isMounted())
|
|
61
|
+
return;
|
|
62
|
+
session.engine.dispatch({
|
|
63
|
+
type: "activity.add",
|
|
64
|
+
level: "warning",
|
|
65
|
+
text: `Conversation state unavailable: ${userFacingError(error)}`,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
}
|
|
38
69
|
async function loadInitialSettings(lifecycleOptions = {}) {
|
|
39
70
|
try {
|
|
40
71
|
const settings = await session.settings.loadInitial({
|
|
@@ -127,6 +158,7 @@ export function createAgentEngine(options) {
|
|
|
127
158
|
subscribe: session.engine.subscribe,
|
|
128
159
|
dispatch: session.engine.dispatch,
|
|
129
160
|
maybeCheckForUpdate,
|
|
161
|
+
loadInitialConversation,
|
|
130
162
|
loadInitialSettings,
|
|
131
163
|
loadWorkdir,
|
|
132
164
|
refreshAuth,
|
package/dist/engine/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export type { AgentEngineApp, AgentEngineAppOptions, AgentEngineLifecycleOptions, } from "./agent-engine.js";
|
|
2
2
|
export { createAgentEngine, } from "./agent-engine.js";
|
|
3
3
|
export type { AgentRunOptions, AgentTurnEvent, LocalToolApprovalRequest, WorkdirAccessMode, } from "../agent.js";
|
|
4
|
-
export { agentResponseFailureMessage, agentTurnEventFromStreamEvent, clearPresetToolCatalogCache, conversationSummary, deleteConversation, getConversation, isAvailablePreset, listAvailablePresets, listConversations, resumeAgentAfterLocalApproval, runAgent, resolveAgentRequestTools, runAgentTurn, } from "../agent.js";
|
|
4
|
+
export { agentResponseFailureMessage, agentTurnEventFromStreamEvent, clearPresetToolCatalogCache, conversationSummary, deleteConversation, ensureConversation, getConversation, isAvailablePreset, listAvailablePresets, listConversations, resumeAgentAfterLocalApproval, runAgent, resolveAgentRequestTools, runAgentTurn, startFreshConversation, } from "../agent.js";
|
|
5
5
|
export type { ChatOptions } from "../chat-options.js";
|
|
6
6
|
export { normalizeChatOptions } from "../chat-options.js";
|
|
7
7
|
export type { AgentEngineServices } from "./services.js";
|
package/dist/engine/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { createAgentEngine, } from "./agent-engine.js";
|
|
2
|
-
export { agentResponseFailureMessage, agentTurnEventFromStreamEvent, clearPresetToolCatalogCache, conversationSummary, deleteConversation, getConversation, isAvailablePreset, listAvailablePresets, listConversations, resumeAgentAfterLocalApproval, runAgent, resolveAgentRequestTools, runAgentTurn, } from "../agent.js";
|
|
2
|
+
export { agentResponseFailureMessage, agentTurnEventFromStreamEvent, clearPresetToolCatalogCache, conversationSummary, deleteConversation, ensureConversation, getConversation, isAvailablePreset, listAvailablePresets, listConversations, resumeAgentAfterLocalApproval, runAgent, resolveAgentRequestTools, runAgentTurn, startFreshConversation, } from "../agent.js";
|
|
3
3
|
export { normalizeChatOptions } from "../chat-options.js";
|
|
4
4
|
export { defaultBaseURL } from "../config.js";
|
|
5
5
|
export { activeProfile, loadAppConfiguration, loadConfig, loadConversationConfiguration, loadWorkbenchPreferences, redactSecret, saveAppConfiguration, saveConfig, saveConversationConfiguration, updateWorkbenchPreferences, } from "../config.js";
|
|
@@ -32,7 +32,7 @@ export function createWorkbenchCommandController(options) {
|
|
|
32
32
|
await startNewConversation(command.name);
|
|
33
33
|
return;
|
|
34
34
|
case "switch_conversation":
|
|
35
|
-
switchConversation(command.name);
|
|
35
|
+
await switchConversation(command.name);
|
|
36
36
|
return;
|
|
37
37
|
case "list_conversations":
|
|
38
38
|
await showConversations();
|
|
@@ -278,17 +278,29 @@ export function createWorkbenchCommandController(options) {
|
|
|
278
278
|
async function startNewConversation(name) {
|
|
279
279
|
const conversation = await options.conversationController.startNewConversation(name, options.options.profile);
|
|
280
280
|
dispatch({ type: "messages.clear" });
|
|
281
|
-
dispatch({
|
|
281
|
+
dispatch({
|
|
282
|
+
type: "conversation.set",
|
|
283
|
+
id: conversation.id,
|
|
284
|
+
name: conversation.name,
|
|
285
|
+
previousResponseId: conversation.previousResponseId,
|
|
286
|
+
status: conversation.status,
|
|
287
|
+
});
|
|
282
288
|
dispatch({
|
|
283
289
|
type: "message.add",
|
|
284
290
|
role: "system",
|
|
285
291
|
text: conversation.message,
|
|
286
292
|
});
|
|
287
293
|
}
|
|
288
|
-
function switchConversation(name) {
|
|
289
|
-
const conversation = options.conversationController.switchConversation(name);
|
|
294
|
+
async function switchConversation(name) {
|
|
295
|
+
const conversation = await options.conversationController.switchConversation(name, options.options.profile);
|
|
290
296
|
dispatch({ type: "messages.clear" });
|
|
291
|
-
dispatch({
|
|
297
|
+
dispatch({
|
|
298
|
+
type: "conversation.set",
|
|
299
|
+
id: conversation.id,
|
|
300
|
+
name: conversation.name,
|
|
301
|
+
previousResponseId: conversation.previousResponseId,
|
|
302
|
+
status: conversation.status,
|
|
303
|
+
});
|
|
292
304
|
dispatch({
|
|
293
305
|
type: "message.add",
|
|
294
306
|
role: "system",
|
|
@@ -1,14 +1,9 @@
|
|
|
1
1
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
2
|
-
import { deleteConversation, listConversations } from "../agent.js";
|
|
2
|
+
import { deleteConversation, ensureConversation, listConversations, startFreshConversation } from "../agent.js";
|
|
3
3
|
export interface WorkbenchConversationController {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
}>;
|
|
8
|
-
switchConversation(name: string): {
|
|
9
|
-
name: string;
|
|
10
|
-
message: string;
|
|
11
|
-
};
|
|
4
|
+
resolveConversation(name: string, profileName?: string): Promise<ConversationSelection>;
|
|
5
|
+
startNewConversation(name: string | undefined, profileName?: string): Promise<ConversationSelection>;
|
|
6
|
+
switchConversation(name: string, profileName?: string): Promise<ConversationSelection>;
|
|
12
7
|
listConversations(profileName?: string): Promise<string>;
|
|
13
8
|
exportTranscript(input: {
|
|
14
9
|
path?: string;
|
|
@@ -16,6 +11,13 @@ export interface WorkbenchConversationController {
|
|
|
16
11
|
conversation: string;
|
|
17
12
|
}): Promise<string>;
|
|
18
13
|
}
|
|
14
|
+
export interface ConversationSelection {
|
|
15
|
+
id: string;
|
|
16
|
+
name: string;
|
|
17
|
+
previousResponseId?: string;
|
|
18
|
+
status: "fresh" | "continued";
|
|
19
|
+
message: string;
|
|
20
|
+
}
|
|
19
21
|
export interface WorkbenchConversationControllerOptions {
|
|
20
22
|
deleteConversationImpl?: typeof deleteConversation;
|
|
21
23
|
listConversationsImpl?: typeof listConversations;
|
|
@@ -23,6 +25,8 @@ export interface WorkbenchConversationControllerOptions {
|
|
|
23
25
|
writeFileImpl?: typeof writeFile;
|
|
24
26
|
now?: () => Date;
|
|
25
27
|
dataDir?: string;
|
|
28
|
+
ensureConversationImpl?: typeof ensureConversation;
|
|
29
|
+
startFreshConversationImpl?: typeof startFreshConversation;
|
|
26
30
|
}
|
|
27
31
|
export declare function createWorkbenchConversationController(options?: WorkbenchConversationControllerOptions): WorkbenchConversationController;
|
|
28
32
|
export declare function defaultTranscriptExportPath(conversation: string, options?: {
|
|
@@ -1,27 +1,31 @@
|
|
|
1
1
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
import { conversationSummary, deleteConversation, listConversations, } from "../agent.js";
|
|
3
|
+
import { conversationSummary, deleteConversation, ensureConversation, listConversations, startFreshConversation, } from "../agent.js";
|
|
4
4
|
import { runtime } from "../runtime/index.js";
|
|
5
5
|
export function createWorkbenchConversationController(options = {}) {
|
|
6
6
|
const deleteConversationImpl = options.deleteConversationImpl ?? deleteConversation;
|
|
7
7
|
const listConversationsImpl = options.listConversationsImpl ?? listConversations;
|
|
8
|
+
const ensureConversationImpl = options.ensureConversationImpl ?? ensureConversation;
|
|
9
|
+
const startFreshConversationImpl = options.startFreshConversationImpl ?? startFreshConversation;
|
|
8
10
|
const mkdirImpl = options.mkdirImpl ?? mkdir;
|
|
9
11
|
const writeFileImpl = options.writeFileImpl ?? writeFile;
|
|
10
12
|
const now = options.now ?? (() => new Date());
|
|
11
13
|
return {
|
|
14
|
+
async resolveConversation(name, profileName) {
|
|
15
|
+
const conversation = await ensureConversationImpl(name, profileName);
|
|
16
|
+
return conversationSelection(conversation, `Conversation "${conversation.name}" is ${conversation.previousResponseId ? `continuing from ${conversation.previousResponseId}` : "fresh"}.`);
|
|
17
|
+
},
|
|
12
18
|
async startNewConversation(name, profileName) {
|
|
13
|
-
const
|
|
14
|
-
await deleteConversationImpl(
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
message: `Started fresh conversation "${conversation}".`,
|
|
18
|
-
};
|
|
19
|
+
const nameToUse = name || createConversationName(now());
|
|
20
|
+
await deleteConversationImpl(nameToUse, profileName);
|
|
21
|
+
const conversation = await startFreshConversationImpl(nameToUse, profileName);
|
|
22
|
+
return conversationSelection(conversation, `Started fresh conversation "${conversation.name}" (${conversation.id}).`);
|
|
19
23
|
},
|
|
20
|
-
switchConversation(name) {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
async switchConversation(name, profileName) {
|
|
25
|
+
const conversation = await ensureConversationImpl(name, profileName);
|
|
26
|
+
return conversationSelection(conversation, conversation.previousResponseId
|
|
27
|
+
? `Switched to conversation "${name}" (${conversation.id}). Continuing from ${conversation.previousResponseId}.`
|
|
28
|
+
: `Switched to fresh conversation "${name}" (${conversation.id}).`);
|
|
25
29
|
},
|
|
26
30
|
async listConversations(profileName) {
|
|
27
31
|
const conversations = await listConversationsImpl(profileName);
|
|
@@ -42,6 +46,17 @@ export function createWorkbenchConversationController(options = {}) {
|
|
|
42
46
|
},
|
|
43
47
|
};
|
|
44
48
|
}
|
|
49
|
+
function conversationSelection(conversation, message) {
|
|
50
|
+
const selection = {
|
|
51
|
+
id: conversation.id,
|
|
52
|
+
name: conversation.name,
|
|
53
|
+
status: conversation.previousResponseId ? "continued" : "fresh",
|
|
54
|
+
message,
|
|
55
|
+
};
|
|
56
|
+
if (conversation.previousResponseId)
|
|
57
|
+
selection.previousResponseId = conversation.previousResponseId;
|
|
58
|
+
return selection;
|
|
59
|
+
}
|
|
45
60
|
export function defaultTranscriptExportPath(conversation, options = {}) {
|
|
46
61
|
const safeConversation = conversation.replace(/[^a-z0-9._-]+/gi, "-").replace(/^-+|-+$/g, "") || "conversation";
|
|
47
62
|
const stamp = (options.now?.() ?? new Date()).toISOString().replace(/[:.]/g, "-");
|
|
@@ -11,6 +11,9 @@ export interface WorkbenchRenderModel {
|
|
|
11
11
|
accessMode: string;
|
|
12
12
|
contextEnabled: boolean;
|
|
13
13
|
conversation: string;
|
|
14
|
+
conversationId: string;
|
|
15
|
+
conversationPreviousResponseId: string;
|
|
16
|
+
conversationStatus: "fresh" | "continued" | "unknown";
|
|
14
17
|
model: string;
|
|
15
18
|
pendingLocalLabel: string;
|
|
16
19
|
preset: string;
|
|
@@ -28,6 +28,9 @@ export function buildWorkbenchRenderModel(input) {
|
|
|
28
28
|
accessMode: input.state.accessMode,
|
|
29
29
|
contextEnabled: input.state.contextEnabled,
|
|
30
30
|
conversation: input.state.currentConversation,
|
|
31
|
+
conversationId: input.state.conversationId || "unresolved",
|
|
32
|
+
conversationPreviousResponseId: input.state.conversationPreviousResponseId || "",
|
|
33
|
+
conversationStatus: input.state.conversationStatus,
|
|
31
34
|
model: input.state.runModel || "auto",
|
|
32
35
|
pendingLocalLabel: pendingLocalLabel(input.state),
|
|
33
36
|
preset: input.state.runPreset || "none",
|
|
@@ -34,6 +34,9 @@ export interface WorkbenchState {
|
|
|
34
34
|
activeAssistantMessageId: string | null;
|
|
35
35
|
pendingLocalTool: LocalToolApproval | null;
|
|
36
36
|
accessMode: WorkdirAccessMode;
|
|
37
|
+
conversationId?: string;
|
|
38
|
+
conversationPreviousResponseId?: string;
|
|
39
|
+
conversationStatus: "fresh" | "continued" | "unknown";
|
|
37
40
|
currentConversation: string;
|
|
38
41
|
runPreset?: string;
|
|
39
42
|
runModel?: string;
|
|
@@ -87,7 +90,10 @@ export type WorkbenchAction = {
|
|
|
87
90
|
mode: WorkdirAccessMode;
|
|
88
91
|
} | {
|
|
89
92
|
type: "conversation.set";
|
|
93
|
+
id?: string;
|
|
90
94
|
name: string;
|
|
95
|
+
previousResponseId?: string;
|
|
96
|
+
status?: "fresh" | "continued" | "unknown";
|
|
91
97
|
} | {
|
|
92
98
|
type: "settings.set";
|
|
93
99
|
settings: Partial<Pick<WorkbenchState, "runPreset" | "runModel" | "renderMode" | "defaultPreset" | "shellIsolation">>;
|
package/dist/workbench/state.js
CHANGED
|
@@ -13,6 +13,9 @@ export function createInitialWorkbenchState(options) {
|
|
|
13
13
|
activeAssistantMessageId: null,
|
|
14
14
|
pendingLocalTool: null,
|
|
15
15
|
accessMode,
|
|
16
|
+
conversationId: undefined,
|
|
17
|
+
conversationPreviousResponseId: undefined,
|
|
18
|
+
conversationStatus: "unknown",
|
|
16
19
|
currentConversation: options.conversation || "default",
|
|
17
20
|
runPreset: options.preset,
|
|
18
21
|
runModel: options.model,
|
|
@@ -132,8 +135,11 @@ export function workbenchReducer(state, action) {
|
|
|
132
135
|
case "conversation.set":
|
|
133
136
|
return {
|
|
134
137
|
...state,
|
|
138
|
+
conversationId: action.id,
|
|
135
139
|
currentConversation: action.name,
|
|
136
|
-
|
|
140
|
+
conversationPreviousResponseId: action.previousResponseId,
|
|
141
|
+
conversationStatus: action.status ?? (action.previousResponseId ? "continued" : "fresh"),
|
|
142
|
+
activities: [...state.activities, newActivity("info", conversationActivityText(action))].slice(-20),
|
|
137
143
|
};
|
|
138
144
|
case "settings.set":
|
|
139
145
|
return {
|
|
@@ -144,6 +150,10 @@ export function workbenchReducer(state, action) {
|
|
|
144
150
|
return state;
|
|
145
151
|
}
|
|
146
152
|
}
|
|
153
|
+
function conversationActivityText(action) {
|
|
154
|
+
const suffix = action.previousResponseId ? ` continues ${action.previousResponseId}` : action.status === "fresh" ? " fresh" : "";
|
|
155
|
+
return `Conversation: ${action.name}${suffix}`;
|
|
156
|
+
}
|
|
147
157
|
function setLocalAccess(state, mode) {
|
|
148
158
|
return {
|
|
149
159
|
...state,
|
package/package.json
CHANGED