@letta-ai/letta-agent-sdk 0.7.8 → 0.8.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 +23 -0
- package/dist/agent-creation.d.ts +2 -1
- package/dist/agent-creation.d.ts.map +1 -1
- package/dist/app-server-management.d.ts +1 -0
- package/dist/app-server-management.d.ts.map +1 -1
- package/dist/app-server-session.d.ts.map +1 -1
- package/dist/client-base.d.ts +12 -0
- package/dist/client-base.d.ts.map +1 -1
- package/dist/client-entry.d.ts +1 -0
- package/dist/client-entry.d.ts.map +1 -1
- package/dist/client-entry.js +515 -2679
- package/dist/client-entry.js.map +17 -15
- package/dist/client.d.ts +4 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/cloud-management.d.ts +3 -2
- package/dist/cloud-management.d.ts.map +1 -1
- package/dist/cloud-session.d.ts +4 -1
- package/dist/cloud-session.d.ts.map +1 -1
- package/dist/index.d.ts +6 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +643 -2639
- package/dist/index.js.map +21 -18
- package/dist/management-types.d.ts +47 -1
- package/dist/management-types.d.ts.map +1 -1
- package/dist/management.d.ts +4 -2
- package/dist/management.d.ts.map +1 -1
- package/dist/query-types.d.ts +25 -0
- package/dist/query-types.d.ts.map +1 -0
- package/dist/query.d.ts +7 -0
- package/dist/query.d.ts.map +1 -0
- package/dist/remote-session-protocol.d.ts +11 -1
- package/dist/remote-session-protocol.d.ts.map +1 -1
- package/dist/remote-turn-coordinator.d.ts.map +1 -1
- package/dist/repository-types.d.ts +89 -0
- package/dist/repository-types.d.ts.map +1 -0
- package/dist/skill-loading.d.ts +84 -0
- package/dist/skill-loading.d.ts.map +1 -0
- package/dist/skill-node.d.ts +28 -0
- package/dist/skill-node.d.ts.map +1 -0
- package/dist/types.d.ts +17 -84
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/agent-creation.ts +37 -1
- package/src/app-server-management.ts +8 -0
- package/src/app-server-session.ts +35 -2
- package/src/client-base.ts +138 -1
- package/src/client-entry.ts +1 -0
- package/src/client.ts +39 -0
- package/src/cloud-management.ts +60 -0
- package/src/cloud-session.ts +84 -16
- package/src/index.ts +18 -0
- package/src/local-app-server.ts +1 -1
- package/src/management-types.ts +58 -1
- package/src/management.ts +28 -1
- package/src/query-types.ts +40 -0
- package/src/query.ts +43 -0
- package/src/remote-client-session-core.ts +1 -1
- package/src/remote-session-protocol.ts +12 -1
- package/src/remote-turn-coordinator.ts +5 -1
- package/src/repository-types.ts +105 -0
- package/src/skill-loading.ts +194 -0
- package/src/skill-node.ts +139 -0
- package/src/types.ts +42 -100
package/src/cloud-session.ts
CHANGED
|
@@ -6,6 +6,11 @@ import {
|
|
|
6
6
|
type AppServerClient,
|
|
7
7
|
} from "@letta-ai/letta-code/app-server-client";
|
|
8
8
|
import { createAgentBody } from "./agent-creation.js";
|
|
9
|
+
import {
|
|
10
|
+
resolveSkillItems,
|
|
11
|
+
skillsHaveSupportFiles,
|
|
12
|
+
type SkillFilesPusher,
|
|
13
|
+
} from "./skill-loading.js";
|
|
9
14
|
import {
|
|
10
15
|
AppServerRuntimeController,
|
|
11
16
|
agentToolNames,
|
|
@@ -78,7 +83,12 @@ type CloudRuntimeStartResponse = ProtocolMessage & {
|
|
|
78
83
|
model?: string | null;
|
|
79
84
|
model_settings?: Record<string, unknown> | null;
|
|
80
85
|
}) | null;
|
|
81
|
-
conversation: (Record<string, unknown> & {
|
|
86
|
+
conversation: (Record<string, unknown> & {
|
|
87
|
+
id?: string;
|
|
88
|
+
agent_id?: string | null;
|
|
89
|
+
model?: string | null;
|
|
90
|
+
model_settings?: Record<string, unknown> | null;
|
|
91
|
+
}) | null;
|
|
82
92
|
error?: string;
|
|
83
93
|
};
|
|
84
94
|
|
|
@@ -143,7 +153,10 @@ export class CloudManagedSandboxExpiredError extends Error {
|
|
|
143
153
|
}
|
|
144
154
|
}
|
|
145
155
|
|
|
146
|
-
type CloudSessionMode = Extract<
|
|
156
|
+
type CloudSessionMode = Extract<
|
|
157
|
+
RuntimeSessionMode,
|
|
158
|
+
{ kind: "session" } | { kind: "agent-free" }
|
|
159
|
+
>;
|
|
147
160
|
|
|
148
161
|
function getWebSocketConstructor(
|
|
149
162
|
websocketOverride?: LettaCodeSocketConstructor,
|
|
@@ -226,7 +239,7 @@ function environmentToRemoteTarget(
|
|
|
226
239
|
function buildCloudStatusWebSocketUrl(params: {
|
|
227
240
|
apiBaseUrl?: string;
|
|
228
241
|
connectionId: string;
|
|
229
|
-
agentId: string;
|
|
242
|
+
agentId: string | null;
|
|
230
243
|
conversationId: string;
|
|
231
244
|
apiKey?: string;
|
|
232
245
|
authMode: "header" | "query";
|
|
@@ -240,7 +253,7 @@ function buildCloudStatusWebSocketUrl(params: {
|
|
|
240
253
|
throw new Error(`Unsupported cloud apiBaseUrl protocol: ${base.protocol}`);
|
|
241
254
|
}
|
|
242
255
|
base.pathname = `/v1/environments/${encodeURIComponent(params.connectionId)}/status/ws`;
|
|
243
|
-
base.searchParams.set("agentId", params.agentId);
|
|
256
|
+
if (params.agentId) base.searchParams.set("agentId", params.agentId);
|
|
244
257
|
base.searchParams.set("conversationId", params.conversationId);
|
|
245
258
|
base.searchParams.set("channel", "stream");
|
|
246
259
|
if (params.authMode === "query" && params.apiKey) {
|
|
@@ -301,12 +314,38 @@ function externalToolsByName(tools: AnyAgentTool[] | undefined): Map<string, Any
|
|
|
301
314
|
export async function createCloudAgent(
|
|
302
315
|
client: Letta,
|
|
303
316
|
agentOptions: CreateAgentOptions,
|
|
317
|
+
pushSkillSupportFiles?: SkillFilesPusher,
|
|
304
318
|
): Promise<string> {
|
|
305
|
-
|
|
319
|
+
// Directory paths were already resolved to inline skills by the client
|
|
320
|
+
// facade; this validates inline skills passed directly.
|
|
321
|
+
const skills = await resolveSkillItems(agentOptions.skills);
|
|
322
|
+
const hasSupportFiles = skillsHaveSupportFiles(skills);
|
|
323
|
+
if (hasSupportFiles && pushSkillSupportFiles === undefined) {
|
|
324
|
+
throw new Error(
|
|
325
|
+
"Skill support files (scripts/, references/) require the Node.js " +
|
|
326
|
+
"package root; the portable client seeds SKILL.md-only skills.",
|
|
327
|
+
);
|
|
328
|
+
}
|
|
329
|
+
const body = await createAgentBody(agentOptions, skills);
|
|
306
330
|
const agent = await client.agents.create(body as AgentCreateParams);
|
|
307
331
|
if (typeof agent.id !== "string" || agent.id.length === 0) {
|
|
308
332
|
throw new Error("Cloud create agent response did not include an agent id.");
|
|
309
333
|
}
|
|
334
|
+
// SKILL.md contents rode the create request as memory blocks; support
|
|
335
|
+
// files (scripts, references) have no block representation and go to the
|
|
336
|
+
// agent's memory git repo in one follow-up commit.
|
|
337
|
+
if (hasSupportFiles && pushSkillSupportFiles) {
|
|
338
|
+
if (typeof client.apiKey !== "string" || client.apiKey.length === 0) {
|
|
339
|
+
throw new Error(
|
|
340
|
+
`Agent ${agent.id} was created, but skill support files need an API ` +
|
|
341
|
+
"key to push to the agent's memory repo and none is configured.",
|
|
342
|
+
);
|
|
343
|
+
}
|
|
344
|
+
await pushSkillSupportFiles(
|
|
345
|
+
{ apiBaseUrl: client.baseURL, apiKey: client.apiKey, agentId: agent.id },
|
|
346
|
+
skills,
|
|
347
|
+
);
|
|
348
|
+
}
|
|
310
349
|
return agent.id;
|
|
311
350
|
}
|
|
312
351
|
|
|
@@ -364,10 +403,12 @@ export class CloudEnvironmentSession extends RemoteClientSessionCore {
|
|
|
364
403
|
const resolved = await this.resolveRuntime();
|
|
365
404
|
const connection = await this.resolveConnectionForRuntime(resolved.runtime).catch(
|
|
366
405
|
async (error: unknown) => {
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
406
|
+
if (resolved.runtime.agent_id) {
|
|
407
|
+
await this.cleanupSessionRepositories(
|
|
408
|
+
resolved.runtime.agent_id,
|
|
409
|
+
resolved.runtime.conversation_id,
|
|
410
|
+
);
|
|
411
|
+
}
|
|
371
412
|
throw error;
|
|
372
413
|
},
|
|
373
414
|
);
|
|
@@ -393,10 +434,12 @@ export class CloudEnvironmentSession extends RemoteClientSessionCore {
|
|
|
393
434
|
} catch (error) {
|
|
394
435
|
await this.closeMcpBridge();
|
|
395
436
|
await this.cleanupManagedSandbox();
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
437
|
+
if (resolved.runtime.agent_id) {
|
|
438
|
+
await this.cleanupSessionRepositories(
|
|
439
|
+
resolved.runtime.agent_id,
|
|
440
|
+
resolved.runtime.conversation_id,
|
|
441
|
+
);
|
|
442
|
+
}
|
|
400
443
|
throw error;
|
|
401
444
|
}
|
|
402
445
|
}
|
|
@@ -438,8 +481,16 @@ export class CloudEnvironmentSession extends RemoteClientSessionCore {
|
|
|
438
481
|
clientToolset,
|
|
439
482
|
),
|
|
440
483
|
runtime: response.runtime,
|
|
441
|
-
model:
|
|
442
|
-
|
|
484
|
+
model:
|
|
485
|
+
typeof response.agent?.model === "string"
|
|
486
|
+
? response.agent.model
|
|
487
|
+
: typeof response.conversation?.model === "string"
|
|
488
|
+
? response.conversation.model
|
|
489
|
+
: "",
|
|
490
|
+
modelSettings:
|
|
491
|
+
response.agent?.model_settings ??
|
|
492
|
+
response.conversation?.model_settings ??
|
|
493
|
+
null,
|
|
443
494
|
...(availableTools !== undefined ? { tools: availableTools } : {}),
|
|
444
495
|
...(skillSources !== undefined ? { skillSources: [...skillSources] } : {}),
|
|
445
496
|
};
|
|
@@ -590,11 +641,11 @@ export class CloudEnvironmentSession extends RemoteClientSessionCore {
|
|
|
590
641
|
name: SDK_AGENT_ORIGIN,
|
|
591
642
|
title: "Letta Agent SDK",
|
|
592
643
|
},
|
|
593
|
-
agent_id: runtime.agent_id,
|
|
594
644
|
conversation_id: runtime.conversation_id,
|
|
595
645
|
recover_approvals: false,
|
|
596
646
|
force_device_status: true,
|
|
597
647
|
};
|
|
648
|
+
if (runtime.agent_id) command.agent_id = runtime.agent_id;
|
|
598
649
|
|
|
599
650
|
const mode = mapPermissionMode(options.permissionMode);
|
|
600
651
|
if (mode) command.mode = mode;
|
|
@@ -676,6 +727,18 @@ export class CloudEnvironmentSession extends RemoteClientSessionCore {
|
|
|
676
727
|
}
|
|
677
728
|
|
|
678
729
|
private async resolveRuntime(): Promise<{ runtime: RuntimeScope }> {
|
|
730
|
+
if (this.cloudMode.kind === "agent-free") {
|
|
731
|
+
if (!this.cloudMode.conversationId) {
|
|
732
|
+
throw new Error("Cloud agent-free sessions require a conversation id.");
|
|
733
|
+
}
|
|
734
|
+
return {
|
|
735
|
+
runtime: {
|
|
736
|
+
agent_id: null,
|
|
737
|
+
conversation_id: this.cloudMode.conversationId,
|
|
738
|
+
},
|
|
739
|
+
};
|
|
740
|
+
}
|
|
741
|
+
|
|
679
742
|
let agentId = this.cloudMode.agentId;
|
|
680
743
|
let conversationId = this.cloudMode.conversationId;
|
|
681
744
|
|
|
@@ -890,6 +953,11 @@ export class CloudEnvironmentSession extends RemoteClientSessionCore {
|
|
|
890
953
|
private async createManagedSandboxConnection(
|
|
891
954
|
runtime: RuntimeScope,
|
|
892
955
|
): Promise<ResolvedCloudConnection> {
|
|
956
|
+
if (!runtime.agent_id) {
|
|
957
|
+
throw new Error(
|
|
958
|
+
"Agent-free queries require an explicit Cloud computer; managed sandboxes are agent-scoped.",
|
|
959
|
+
);
|
|
960
|
+
}
|
|
893
961
|
// Scope the managed sandbox to the conversation when one exists: the
|
|
894
962
|
// server treats create-with-conversationId as create-or-resume, so
|
|
895
963
|
// sessions of the same conversation share one sandbox and sessions of
|
package/src/index.ts
CHANGED
|
@@ -39,6 +39,7 @@ import type {
|
|
|
39
39
|
SDKResultMessage,
|
|
40
40
|
SendMessage,
|
|
41
41
|
} from "./types.js";
|
|
42
|
+
import type { Query, QueryParams } from "./query-types.js";
|
|
42
43
|
import { validateCreateSessionOptions, validateCreateAgentOptions } from "./validation.js";
|
|
43
44
|
|
|
44
45
|
// Re-export types
|
|
@@ -94,6 +95,8 @@ export type {
|
|
|
94
95
|
SessionDiffHunk,
|
|
95
96
|
SessionDiffPreview,
|
|
96
97
|
SkillSource,
|
|
98
|
+
SkillItem,
|
|
99
|
+
AgentSkill,
|
|
97
100
|
DreamingOptions,
|
|
98
101
|
SessionDreamingOptions,
|
|
99
102
|
DreamingTrigger,
|
|
@@ -152,6 +155,11 @@ export type {
|
|
|
152
155
|
McpSseServerConfig,
|
|
153
156
|
McpServers,
|
|
154
157
|
} from "./types.js";
|
|
158
|
+
export type {
|
|
159
|
+
AgentFreeQueryOptions,
|
|
160
|
+
Query,
|
|
161
|
+
QueryParams,
|
|
162
|
+
} from "./query-types.js";
|
|
155
163
|
export type * from "./sandbox-files.js";
|
|
156
164
|
export type {
|
|
157
165
|
AgentRepositoriesClient,
|
|
@@ -174,6 +182,8 @@ export type {
|
|
|
174
182
|
ConversationMessagesResult,
|
|
175
183
|
DetachAgentRepositoryOptions,
|
|
176
184
|
AgentRepositoryPermissions,
|
|
185
|
+
EnqueueMessageOptions,
|
|
186
|
+
EnqueueMessageResult,
|
|
177
187
|
} from "./management-types.js";
|
|
178
188
|
|
|
179
189
|
export { RepositoriesClient } from "./repositories.js";
|
|
@@ -323,6 +333,14 @@ export async function prompt(
|
|
|
323
333
|
}
|
|
324
334
|
}
|
|
325
335
|
|
|
336
|
+
/** Run an agent-free query in a new ephemeral conversation. */
|
|
337
|
+
export function query(params: QueryParams): Query {
|
|
338
|
+
return new LettaAgentClient({
|
|
339
|
+
backend: "local",
|
|
340
|
+
appServer: { harnessBackend: "api" },
|
|
341
|
+
}).query(params);
|
|
342
|
+
}
|
|
343
|
+
|
|
326
344
|
// ═══════════════════════════════════════════════════════════════
|
|
327
345
|
// SESSIONLESS APIs
|
|
328
346
|
// ═══════════════════════════════════════════════════════════════
|
package/src/local-app-server.ts
CHANGED
package/src/management-types.ts
CHANGED
|
@@ -12,7 +12,12 @@ import type {
|
|
|
12
12
|
ConversationUpdateParams,
|
|
13
13
|
} from "@letta-ai/letta-client/resources/conversations/conversations";
|
|
14
14
|
import type { MessageListParams } from "@letta-ai/letta-client/resources/conversations/messages";
|
|
15
|
-
import type {
|
|
15
|
+
import type {
|
|
16
|
+
ListMessagesResult,
|
|
17
|
+
ListModelsResult,
|
|
18
|
+
PermissionMode,
|
|
19
|
+
SendMessage,
|
|
20
|
+
} from "./types.js";
|
|
16
21
|
|
|
17
22
|
/** Agent state returned by either the Cloud API or Letta Code app-server. */
|
|
18
23
|
export type LettaAgent = AgentState;
|
|
@@ -100,6 +105,34 @@ export interface ConversationMessagesOptions {
|
|
|
100
105
|
|
|
101
106
|
export type ConversationMessagesResult = ListMessagesResult;
|
|
102
107
|
|
|
108
|
+
export interface EnqueueMessageOptions {
|
|
109
|
+
/**
|
|
110
|
+
* Required when `conversationId` is `"default"`; identifies the agent whose
|
|
111
|
+
* default conversation receives the message. Ignored otherwise.
|
|
112
|
+
*/
|
|
113
|
+
agentId?: string;
|
|
114
|
+
/**
|
|
115
|
+
* Correlation id for this message. Reuse the same value when retrying an
|
|
116
|
+
* enqueue so the listener can deduplicate delivery; the SDK generates one
|
|
117
|
+
* when omitted. Matches the `otid` contract of `session.send()`.
|
|
118
|
+
*/
|
|
119
|
+
clientMessageId?: string;
|
|
120
|
+
/** Permission mode the listener applies before the turn when the runtime is cold. */
|
|
121
|
+
permissionMode?: PermissionMode;
|
|
122
|
+
/** Working directory for the runtime; `null` resets to the listener boot cwd. */
|
|
123
|
+
workingDirectory?: string | null;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/** The Cloud API's 202 acceptance of an enqueued message. */
|
|
127
|
+
export interface EnqueueMessageResult {
|
|
128
|
+
/** The correlation id the message was accepted under (caller-supplied or SDK-generated). */
|
|
129
|
+
clientMessageId: string;
|
|
130
|
+
/** Temporal workflow id of the conversation queue that owns delivery. */
|
|
131
|
+
workflowId: string;
|
|
132
|
+
/** Super run id tracking the message from queue through delivery and completion. */
|
|
133
|
+
superRunId: string;
|
|
134
|
+
}
|
|
135
|
+
|
|
103
136
|
export type AgentRepositoryPermissions = "read" | "read_write";
|
|
104
137
|
export type AgentRepositoryRecompileTarget = "default" | false;
|
|
105
138
|
|
|
@@ -193,4 +226,28 @@ export interface ConversationsClient {
|
|
|
193
226
|
conversationId: string,
|
|
194
227
|
options?: ConversationMessagesOptions,
|
|
195
228
|
): Promise<ConversationMessagesResult>;
|
|
229
|
+
/**
|
|
230
|
+
* Hand a user message to the server for delivery instead of sending it over
|
|
231
|
+
* a session. Cloud backend only.
|
|
232
|
+
*
|
|
233
|
+
* The returned promise resolves once the Cloud API has durably accepted the
|
|
234
|
+
* message (HTTP 202): from that point the server owns delivery. It ensures
|
|
235
|
+
* or resumes the conversation's sandbox, delivers the message to the
|
|
236
|
+
* listener with acknowledgement and retries, and tracks the whole lifecycle
|
|
237
|
+
* as a super run. The caller may exit immediately; the turn runs
|
|
238
|
+
* server-side. This is the send path chat.letta.com uses.
|
|
239
|
+
*
|
|
240
|
+
* Use `enqueue()` when you cannot hold a connection open for the length of
|
|
241
|
+
* a turn, such as serverless webhook handlers. Use a session's `send()` and
|
|
242
|
+
* `stream()` when you want to stream the turn's output; a session delivers
|
|
243
|
+
* input over its open socket and does not survive the caller.
|
|
244
|
+
*
|
|
245
|
+
* Pass `"default"` as `conversationId` with `options.agentId` to target an
|
|
246
|
+
* agent's default conversation.
|
|
247
|
+
*/
|
|
248
|
+
enqueue(
|
|
249
|
+
conversationId: string,
|
|
250
|
+
message: SendMessage,
|
|
251
|
+
options?: EnqueueMessageOptions,
|
|
252
|
+
): Promise<EnqueueMessageResult>;
|
|
196
253
|
}
|
package/src/management.ts
CHANGED
|
@@ -15,6 +15,8 @@ import type {
|
|
|
15
15
|
ConversationsClient,
|
|
16
16
|
ConversationMessagesResult,
|
|
17
17
|
CreateConversationOptions,
|
|
18
|
+
EnqueueMessageOptions,
|
|
19
|
+
EnqueueMessageResult,
|
|
18
20
|
ForkConversationOptions,
|
|
19
21
|
LettaAgent,
|
|
20
22
|
LettaConversation,
|
|
@@ -25,7 +27,7 @@ import type {
|
|
|
25
27
|
UpdateConversationOptions,
|
|
26
28
|
ConversationMessagesOptions,
|
|
27
29
|
} from "./management-types.js";
|
|
28
|
-
import type { ListModelsResult } from "./types.js";
|
|
30
|
+
import type { ListModelsResult, SendMessage } from "./types.js";
|
|
29
31
|
|
|
30
32
|
export interface ManagementTransport {
|
|
31
33
|
listAgents(query: AgentListParams): Promise<LettaAgent[]>;
|
|
@@ -57,6 +59,12 @@ export interface ManagementTransport {
|
|
|
57
59
|
conversationId: string,
|
|
58
60
|
query: MessageListParams,
|
|
59
61
|
): Promise<ConversationMessagesResult>;
|
|
62
|
+
/** Cloud only. Non-cloud transports reject with a backend error. */
|
|
63
|
+
enqueueConversationMessage(
|
|
64
|
+
conversationId: string,
|
|
65
|
+
message: SendMessage,
|
|
66
|
+
options: EnqueueMessageOptions,
|
|
67
|
+
): Promise<EnqueueMessageResult>;
|
|
60
68
|
}
|
|
61
69
|
|
|
62
70
|
type TransportProvider = () => ManagementTransport;
|
|
@@ -227,5 +235,24 @@ export function createConversationsClient(
|
|
|
227
235
|
conversationId,
|
|
228
236
|
conversationMessagesQuery(options),
|
|
229
237
|
),
|
|
238
|
+
enqueue: async (conversationId, message, options = {}) => {
|
|
239
|
+
assertNonEmptyId(conversationId, "conversation id");
|
|
240
|
+
if (conversationId.trim() === "default" && !options.agentId) {
|
|
241
|
+
throw new Error(
|
|
242
|
+
'enqueue("default", ...) requires options.agentId to identify the agent.',
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
if (options.agentId !== undefined) {
|
|
246
|
+
assertNonEmptyId(options.agentId, "agent id");
|
|
247
|
+
}
|
|
248
|
+
if (options.clientMessageId !== undefined) {
|
|
249
|
+
assertNonEmptyId(options.clientMessageId, "client message id");
|
|
250
|
+
}
|
|
251
|
+
return await transport().enqueueConversationMessage(
|
|
252
|
+
conversationId,
|
|
253
|
+
message,
|
|
254
|
+
options,
|
|
255
|
+
);
|
|
256
|
+
},
|
|
230
257
|
};
|
|
231
258
|
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
LettaCodeClientSessionOptions,
|
|
3
|
+
SDKMessage,
|
|
4
|
+
SendMessage,
|
|
5
|
+
} from "./types.js";
|
|
6
|
+
|
|
7
|
+
/** Options for an agent-free query backed by an ephemeral conversation. */
|
|
8
|
+
export interface AgentFreeQueryOptions
|
|
9
|
+
extends Omit<
|
|
10
|
+
LettaCodeClientSessionOptions,
|
|
11
|
+
| "model"
|
|
12
|
+
| "reasoningEffort"
|
|
13
|
+
| "stateless"
|
|
14
|
+
| "dreaming"
|
|
15
|
+
| "resources"
|
|
16
|
+
| "filesystemConfinement"
|
|
17
|
+
> {
|
|
18
|
+
/** Model handle persisted on the ephemeral conversation. */
|
|
19
|
+
model: string;
|
|
20
|
+
/** Complete system prompt for the ephemeral conversation. */
|
|
21
|
+
system: string;
|
|
22
|
+
/** Provider model settings persisted on the ephemeral conversation. */
|
|
23
|
+
modelSettings?: Record<string, unknown>;
|
|
24
|
+
/** Optional context-window limit persisted on the ephemeral conversation. */
|
|
25
|
+
contextWindowLimit?: number | null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Input accepted by query(). */
|
|
29
|
+
export interface QueryParams {
|
|
30
|
+
prompt: SendMessage;
|
|
31
|
+
options: AgentFreeQueryOptions;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Stream returned by query(), with controls for long-running execution. */
|
|
35
|
+
export interface Query extends AsyncGenerator<SDKMessage, void, unknown> {
|
|
36
|
+
/** Interrupt the active turn without closing the query session. */
|
|
37
|
+
interrupt(): Promise<void>;
|
|
38
|
+
/** Close the query and release its underlying session. */
|
|
39
|
+
close(): void;
|
|
40
|
+
}
|
package/src/query.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { AgentFreeQueryOptions, Query, QueryParams } from "./query-types.js";
|
|
2
|
+
import type { LettaCodeSession, SDKMessage } from "./types.js";
|
|
3
|
+
|
|
4
|
+
type CreateAgentFreeSession = (
|
|
5
|
+
options: AgentFreeQueryOptions,
|
|
6
|
+
) => Promise<LettaCodeSession>;
|
|
7
|
+
|
|
8
|
+
/** Create one agent-free ephemeral conversation and stream its query result. */
|
|
9
|
+
export function createQuery(
|
|
10
|
+
createSession: CreateAgentFreeSession,
|
|
11
|
+
params: QueryParams,
|
|
12
|
+
): Query {
|
|
13
|
+
let session: LettaCodeSession | null = null;
|
|
14
|
+
let closed = false;
|
|
15
|
+
|
|
16
|
+
const iterator = (async function* runQuery(): AsyncGenerator<
|
|
17
|
+
SDKMessage,
|
|
18
|
+
void,
|
|
19
|
+
unknown
|
|
20
|
+
> {
|
|
21
|
+
try {
|
|
22
|
+
session = await createSession(params.options);
|
|
23
|
+
if (closed) return;
|
|
24
|
+
await session.send(params.prompt);
|
|
25
|
+
yield* session.stream();
|
|
26
|
+
} finally {
|
|
27
|
+
closed = true;
|
|
28
|
+
session?.close();
|
|
29
|
+
}
|
|
30
|
+
})();
|
|
31
|
+
|
|
32
|
+
return Object.assign(iterator, {
|
|
33
|
+
async interrupt(): Promise<void> {
|
|
34
|
+
await session?.abort();
|
|
35
|
+
},
|
|
36
|
+
close(): void {
|
|
37
|
+
if (closed) return;
|
|
38
|
+
closed = true;
|
|
39
|
+
session?.close();
|
|
40
|
+
void iterator.return();
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
}
|
|
@@ -166,7 +166,7 @@ export abstract class RemoteClientSessionCore implements LettaCodeSession {
|
|
|
166
166
|
this.runtime = init.runtime;
|
|
167
167
|
this._agentId = init.runtime.agent_id;
|
|
168
168
|
this._conversationId = init.runtime.conversation_id;
|
|
169
|
-
this._sessionId = `${init.runtime.agent_id}:${init.runtime.conversation_id}
|
|
169
|
+
this._sessionId = init.runtime.agent_id ? `${init.runtime.agent_id}:${init.runtime.conversation_id}` : init.runtime.conversation_id;
|
|
170
170
|
this._modelSettings = init.modelSettings ?? null;
|
|
171
171
|
this._model =
|
|
172
172
|
typeof init.model === "string"
|
|
@@ -23,7 +23,7 @@ import type {
|
|
|
23
23
|
} from "./types.js";
|
|
24
24
|
|
|
25
25
|
export type RuntimeScope = {
|
|
26
|
-
agent_id: string;
|
|
26
|
+
agent_id: string | null;
|
|
27
27
|
conversation_id: string;
|
|
28
28
|
};
|
|
29
29
|
|
|
@@ -35,6 +35,17 @@ export type ProtocolMessage = Record<string, unknown> & {
|
|
|
35
35
|
|
|
36
36
|
export type RuntimeSessionMode =
|
|
37
37
|
| { kind: "create-agent"; options: CreateAgentOptions }
|
|
38
|
+
| {
|
|
39
|
+
kind: "agent-free";
|
|
40
|
+
conversationId?: string;
|
|
41
|
+
createConversation?: {
|
|
42
|
+
model: string;
|
|
43
|
+
system: string;
|
|
44
|
+
modelSettings?: Record<string, unknown>;
|
|
45
|
+
contextWindowLimit?: number | null;
|
|
46
|
+
};
|
|
47
|
+
options: LettaCodeClientSessionOptions;
|
|
48
|
+
}
|
|
38
49
|
| {
|
|
39
50
|
kind: "session";
|
|
40
51
|
agentId?: string;
|
|
@@ -614,12 +614,16 @@ export class RemoteTurnCoordinator {
|
|
|
614
614
|
const errorCode = approvalConflict
|
|
615
615
|
? "approval_conflict"
|
|
616
616
|
: (turn.errorCode ?? toSdkErrorCode(stopReason));
|
|
617
|
+
const publicError =
|
|
618
|
+
errorCode && errorCode !== "error"
|
|
619
|
+
? errorCode
|
|
620
|
+
: (turn.detail ?? stopReason ?? "error");
|
|
617
621
|
|
|
618
622
|
return {
|
|
619
623
|
type: "result",
|
|
620
624
|
success,
|
|
621
625
|
result: success ? tracker?.assistantText || undefined : undefined,
|
|
622
|
-
error: success ? undefined :
|
|
626
|
+
error: success ? undefined : publicError,
|
|
623
627
|
errorCode: success ? undefined : (errorCode ?? "error"),
|
|
624
628
|
approvalConflict: approvalConflict || undefined,
|
|
625
629
|
recoverable: approvalConflict
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Letta-hosted repository API types, used by RepositoriesClient and
|
|
3
|
+
* AgentRepositoriesClient. Kept beside their implementation
|
|
4
|
+
* (repositories.ts) and re-exported from types.ts.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export interface Repository {
|
|
8
|
+
id: string;
|
|
9
|
+
name: string;
|
|
10
|
+
createdAt: string;
|
|
11
|
+
updatedAt: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface CreateRepositoryParams {
|
|
15
|
+
name: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface ListRepositoriesParams {
|
|
19
|
+
limit?: number;
|
|
20
|
+
offset?: number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface ListRepositoriesResult {
|
|
24
|
+
repositories: Repository[];
|
|
25
|
+
hasNextPage: boolean;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface RepositoryResource {
|
|
29
|
+
type: "repository";
|
|
30
|
+
repositoryId: string;
|
|
31
|
+
/**
|
|
32
|
+
* Whether to trigger a system-prompt recompile after attaching (and after
|
|
33
|
+
* detaching on cleanup) so the session's conversation does not retain
|
|
34
|
+
* stale repository projections. Defaults to `true`.
|
|
35
|
+
*/
|
|
36
|
+
recompile?: boolean;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface RepositoryFileEntry {
|
|
40
|
+
path: string;
|
|
41
|
+
type: "file" | "directory";
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface ListRepositoryFilesParams {
|
|
45
|
+
pathPrefix?: string;
|
|
46
|
+
depth?: number;
|
|
47
|
+
ref?: string;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface ListRepositoryFilesResult {
|
|
51
|
+
files: RepositoryFileEntry[];
|
|
52
|
+
ref: string;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface CreateRepositoryFileParams {
|
|
56
|
+
path: string;
|
|
57
|
+
content: string;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface RepositoryFile {
|
|
61
|
+
path: string;
|
|
62
|
+
content: string;
|
|
63
|
+
contentSha256: string;
|
|
64
|
+
ref?: string;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export interface UpdateRepositoryFileParams {
|
|
68
|
+
path: string;
|
|
69
|
+
content?: string;
|
|
70
|
+
newPath?: string;
|
|
71
|
+
precondition?: {
|
|
72
|
+
contentSha256: string;
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export interface RepositoryFileMutationResult {
|
|
77
|
+
path: string;
|
|
78
|
+
contentSha256: string;
|
|
79
|
+
commitSha: string;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export interface DeleteRepositoryFileParams {
|
|
83
|
+
path: string;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export interface DeleteRepositoryFileResult {
|
|
87
|
+
success: boolean;
|
|
88
|
+
commitSha: string;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export interface RepositoryVersion {
|
|
92
|
+
sha: string;
|
|
93
|
+
message: string;
|
|
94
|
+
timestamp: string;
|
|
95
|
+
author_name: string | null;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export interface ListRepositoryVersionsParams {
|
|
99
|
+
path?: string;
|
|
100
|
+
limit?: number;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export interface GetRepositoryVersionParams {
|
|
104
|
+
path: string;
|
|
105
|
+
}
|