@letta-ai/letta-agent-sdk 0.6.1 → 0.6.2
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-creation.d.ts +3 -7
- package/dist/agent-creation.d.ts.map +1 -1
- package/dist/app-server-session.d.ts +0 -5
- package/dist/app-server-session.d.ts.map +1 -1
- package/dist/client-entry.js +237 -305
- package/dist/client-entry.js.map +9 -9
- package/dist/cloud-session.d.ts.map +1 -1
- package/dist/index.js +238 -306
- package/dist/index.js.map +10 -10
- package/dist/remote-client-session-core.d.ts +20 -0
- package/dist/remote-client-session-core.d.ts.map +1 -1
- package/dist/remote-turn-coordinator.d.ts +10 -0
- package/dist/remote-turn-coordinator.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/agent-creation.ts +93 -55
- package/src/app-server-session.ts +4 -151
- package/src/cloud-session.ts +3 -1
- package/src/remote-client-session-core.ts +34 -0
- package/src/remote-turn-coordinator.ts +27 -0
|
@@ -17,6 +17,7 @@ export declare abstract class RemoteClientSessionCore implements LettaCodeSessio
|
|
|
17
17
|
private readonly requestTimeoutMs;
|
|
18
18
|
private initializePromise;
|
|
19
19
|
private removeMessageHandler;
|
|
20
|
+
private detachTransportDisconnect;
|
|
20
21
|
private readonly turns;
|
|
21
22
|
private toolNames;
|
|
22
23
|
private deviceStatusListeners;
|
|
@@ -63,6 +64,25 @@ export declare abstract class RemoteClientSessionCore implements LettaCodeSessio
|
|
|
63
64
|
changeDeviceState(updates: ChangeDeviceStateOptions): Promise<void>;
|
|
64
65
|
updateToolset(toolsetPreference: string): Promise<void>;
|
|
65
66
|
protected abstract initializeRuntimeController(): Promise<RuntimeSessionInit>;
|
|
67
|
+
/**
|
|
68
|
+
* Fail the session when its transport drops unexpectedly.
|
|
69
|
+
*
|
|
70
|
+
* Without this an in-flight turn parks forever: nextMessage() only settles
|
|
71
|
+
* through the coordinator, and the socket's own pending-request rejection
|
|
72
|
+
* covers request/response commands, not streaming turns.
|
|
73
|
+
*
|
|
74
|
+
* The session is not revived — the runtime lived on the dead socket. The
|
|
75
|
+
* caller observes the error and rebuilds via resumeSession().
|
|
76
|
+
*
|
|
77
|
+
* Subclasses call this only once their runtime is live: a drop before that
|
|
78
|
+
* already surfaces as a rejected connect or runtime-start, and failing the
|
|
79
|
+
* session there would defeat initialize()'s retry path. Explicit closes do
|
|
80
|
+
* not notify, so this fires for faults only. Detaching stays here so every
|
|
81
|
+
* teardown path — clean close and failed initialize alike — covers it.
|
|
82
|
+
*/
|
|
83
|
+
protected watchTransportDisconnect(client: {
|
|
84
|
+
onDisconnect(handler: () => void): () => void;
|
|
85
|
+
}): void;
|
|
66
86
|
protected afterRuntimeInitialized(): Promise<void>;
|
|
67
87
|
protected beforeTurn(): Promise<void>;
|
|
68
88
|
protected onCoreClose(): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remote-client-session-core.d.ts","sourceRoot":"","sources":["../src/remote-client-session-core.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,qBAAqB,EACrB,oBAAoB,EACpB,wBAAwB,EACxB,kBAAkB,EAClB,sBAAsB,EACtB,6BAA6B,EAC7B,gBAAgB,EAEhB,gBAAgB,EAChB,mBAAmB,EACnB,kBAAkB,EAClB,8BAA8B,EAC9B,6BAA6B,EAC7B,yBAAyB,EACzB,cAAc,EACd,UAAU,EACV,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EAChB,kBAAkB,EAClB,WAAW,EACX,mBAAmB,EACnB,kBAAkB,EAClB,iBAAiB,EAClB,MAAM,YAAY,CAAC;AAGpB,OAAO,EACL,aAAa,EACb,4BAA4B,EAC5B,iBAAiB,EACjB,uBAAuB,EACvB,oBAAoB,GACrB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAWL,KAAK,6BAA6B,EAClC,KAAK,6BAA6B,EAClC,KAAK,YAAY,EACjB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EAExB,MAAM,8BAA8B,CAAC;AACtC,YAAY,EACV,eAAe,EACf,6BAA6B,EAC7B,qBAAqB,EACrB,YAAY,EACZ,sBAAsB,EACtB,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,8BAA8B,CAAC;AAEtC,8BAAsB,uBAAwB,YAAW,gBAAgB;
|
|
1
|
+
{"version":3,"file":"remote-client-session-core.d.ts","sourceRoot":"","sources":["../src/remote-client-session-core.ts"],"names":[],"mappings":"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"}
|
|
@@ -35,6 +35,16 @@ export declare class RemoteTurnCoordinator {
|
|
|
35
35
|
markAbortRequested(): void;
|
|
36
36
|
handleProtocolMessage(message: ProtocolMessage, runtime: RuntimeScope): void;
|
|
37
37
|
nextMessage(): Promise<SDKMessage | null>;
|
|
38
|
+
/**
|
|
39
|
+
* Close after the transport dropped, surfacing the failure to stream
|
|
40
|
+
* consumers first.
|
|
41
|
+
*
|
|
42
|
+
* A plain close() resolves waiting consumers with `null`, which is
|
|
43
|
+
* indistinguishable from a conversation ending normally. A dead socket
|
|
44
|
+
* cannot deliver a turn-scoped failure of its own, so the error is
|
|
45
|
+
* synthesized here before the queue drains.
|
|
46
|
+
*/
|
|
47
|
+
closeWithError(detail: string): void;
|
|
38
48
|
close(): void;
|
|
39
49
|
private activateTurn;
|
|
40
50
|
private activateNextTurnFromProtocol;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remote-turn-coordinator.d.ts","sourceRoot":"","sources":["../src/remote-turn-coordinator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,UAAU,EAIV,mBAAmB,EACpB,MAAM,YAAY,CAAC;AACpB,OAAO,EAoBL,KAAK,eAAe,EACpB,KAAK,YAAY,EAEjB,KAAK,WAAW,EACjB,MAAM,8BAA8B,CAAC;AAEtC,KAAK,2BAA2B,GAAG;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC,cAAc,CAAC,MAAM,EAAE,mBAAmB,GAAG,IAAI,CAAC;CACnD,CAAC;AAEF;;;;;;GAMG;AACH,qBAAa,qBAAqB;IAChC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAqB;IACtD,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAU;IACnD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAwC;IACvE,OAAO,CAAC,WAAW,CAAoB;IACvC,OAAO,CAAC,eAAe,CAAmD;IAC1E,OAAO,CAAC,UAAU,CAA4B;IAC9C,OAAO,CAAC,YAAY,CAAqB;IACzC,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,oBAAoB,CAAK;IACjC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,oBAAoB,CAAK;gBAErB,MAAM,EAAE,2BAA2B;IAO/C,IAAI,mBAAmB,IAAI,MAAM,CAEhC;IAED,eAAe,IAAI,OAAO;IAI1B,aAAa,CAAC,OAAO,EAAE,YAAY,GAAG,WAAW;IAuBjD,iBAAiB,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI;IAU1C,kBAAkB,IAAI,IAAI;IAI1B,qBAAqB,CAAC,OAAO,EAAE,eAAe,EAAE,OAAO,EAAE,YAAY,GAAG,IAAI;IAsC5E,WAAW,IAAI,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IASzC,KAAK,IAAI,IAAI;IAYb,OAAO,CAAC,YAAY;IAYpB,OAAO,CAAC,4BAA4B;IAQpC,OAAO,CAAC,QAAQ;IAoBhB,OAAO,CAAC,kBAAkB;IAW1B,OAAO,CAAC,uBAAuB;IAiD/B,OAAO,CAAC,uBAAuB;IAiC/B,OAAO,CAAC,oBAAoB;IA0K5B,OAAO,CAAC,cAAc;IAqCtB,OAAO,CAAC,OAAO;IASf,OAAO,CAAC,UAAU;CAKnB"}
|
|
1
|
+
{"version":3,"file":"remote-turn-coordinator.d.ts","sourceRoot":"","sources":["../src/remote-turn-coordinator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,UAAU,EAIV,mBAAmB,EACpB,MAAM,YAAY,CAAC;AACpB,OAAO,EAoBL,KAAK,eAAe,EACpB,KAAK,YAAY,EAEjB,KAAK,WAAW,EACjB,MAAM,8BAA8B,CAAC;AAEtC,KAAK,2BAA2B,GAAG;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC,cAAc,CAAC,MAAM,EAAE,mBAAmB,GAAG,IAAI,CAAC;CACnD,CAAC;AAEF;;;;;;GAMG;AACH,qBAAa,qBAAqB;IAChC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAqB;IACtD,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAU;IACnD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAwC;IACvE,OAAO,CAAC,WAAW,CAAoB;IACvC,OAAO,CAAC,eAAe,CAAmD;IAC1E,OAAO,CAAC,UAAU,CAA4B;IAC9C,OAAO,CAAC,YAAY,CAAqB;IACzC,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,oBAAoB,CAAK;IACjC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,oBAAoB,CAAK;gBAErB,MAAM,EAAE,2BAA2B;IAO/C,IAAI,mBAAmB,IAAI,MAAM,CAEhC;IAED,eAAe,IAAI,OAAO;IAI1B,aAAa,CAAC,OAAO,EAAE,YAAY,GAAG,WAAW;IAuBjD,iBAAiB,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI;IAU1C,kBAAkB,IAAI,IAAI;IAI1B,qBAAqB,CAAC,OAAO,EAAE,eAAe,EAAE,OAAO,EAAE,YAAY,GAAG,IAAI;IAsC5E,WAAW,IAAI,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IASzC;;;;;;;;OAQG;IACH,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAkBpC,KAAK,IAAI,IAAI;IAYb,OAAO,CAAC,YAAY;IAYpB,OAAO,CAAC,4BAA4B;IAQpC,OAAO,CAAC,QAAQ;IAoBhB,OAAO,CAAC,kBAAkB;IAW1B,OAAO,CAAC,uBAAuB;IAiD/B,OAAO,CAAC,uBAAuB;IAiC/B,OAAO,CAAC,oBAAoB;IA0K5B,OAAO,CAAC,cAAc;IAqCtB,OAAO,CAAC,OAAO;IASf,OAAO,CAAC,UAAU;CAKnB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@letta-ai/letta-agent-sdk",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.2",
|
|
4
4
|
"packageManager": "bun@1.3.0",
|
|
5
5
|
"description": "SDK for programmatic control of Letta agents",
|
|
6
6
|
"type": "module",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"@letta-ai/letta-client": "^1.12.1",
|
|
43
|
-
"@letta-ai/letta-code": "0.30.
|
|
43
|
+
"@letta-ai/letta-code": "0.30.5"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@modelcontextprotocol/server-everything": "^2026.7.4",
|
package/src/agent-creation.ts
CHANGED
|
@@ -1,66 +1,104 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
LETTA_CODE_AGENT_TYPE,
|
|
6
|
-
MODEL_PRESETS,
|
|
2
|
+
buildCreateAgentRequest,
|
|
3
|
+
type CreateAgentMemoryBlock,
|
|
4
|
+
type CreateAgentRequest,
|
|
7
5
|
} from "@letta-ai/letta-code/agent-presets";
|
|
8
6
|
import type { CreateAgentOptions } from "./types.js";
|
|
9
7
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
// when they are not present in the bundled catalog.
|
|
22
|
-
if (modelIdentifier.includes("/")) return modelIdentifier;
|
|
8
|
+
function isPresetSystemPrompt(value: string): boolean {
|
|
9
|
+
return [
|
|
10
|
+
"default",
|
|
11
|
+
"letta-claude",
|
|
12
|
+
"letta-codex",
|
|
13
|
+
"letta-gemini",
|
|
14
|
+
"claude",
|
|
15
|
+
"codex",
|
|
16
|
+
"gemini",
|
|
17
|
+
].includes(value);
|
|
18
|
+
}
|
|
23
19
|
|
|
24
|
-
|
|
20
|
+
function assertCreateAgentOptionsSupported(options: CreateAgentOptions): void {
|
|
21
|
+
if (
|
|
22
|
+
options.allowedTools !== undefined ||
|
|
23
|
+
options.disallowedTools !== undefined
|
|
24
|
+
) {
|
|
25
|
+
throw new Error(
|
|
26
|
+
"App-server createAgent() does not yet support allowedTools/disallowedTools.",
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
if (options.canUseTool !== undefined) {
|
|
30
|
+
throw new Error(
|
|
31
|
+
"App-server createAgent() does not yet support canUseTool callbacks.",
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
if (options.systemInfoReminder !== undefined) {
|
|
35
|
+
throw new Error(
|
|
36
|
+
"App-server createAgent() does not yet support systemInfoReminder overrides.",
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
if (options.dreaming?.behavior !== undefined) {
|
|
40
|
+
throw new Error(
|
|
41
|
+
"App-server createAgent() does not yet support dreaming.behavior overrides.",
|
|
42
|
+
);
|
|
43
|
+
}
|
|
25
44
|
}
|
|
26
45
|
|
|
27
|
-
/**
|
|
28
|
-
|
|
29
|
-
*
|
|
30
|
-
* Personality presets are explicit opt-ins. Without one, the SDK builds a
|
|
31
|
-
* generic agent and lets the caller's memory blocks define its identity.
|
|
32
|
-
*/
|
|
33
|
-
export async function buildInitialAgentBody(
|
|
46
|
+
/** Translate SDK convenience options into the canonical Letta Code request. */
|
|
47
|
+
export async function createAgentBody(
|
|
34
48
|
options: CreateAgentOptions,
|
|
35
|
-
): Promise<
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
49
|
+
): Promise<CreateAgentRequest> {
|
|
50
|
+
assertCreateAgentOptionsSupported(options);
|
|
51
|
+
|
|
52
|
+
let system: string | undefined;
|
|
53
|
+
if (options.systemPrompt !== undefined) {
|
|
54
|
+
if (
|
|
55
|
+
typeof options.systemPrompt !== "string" ||
|
|
56
|
+
isPresetSystemPrompt(options.systemPrompt)
|
|
57
|
+
) {
|
|
58
|
+
throw new Error(
|
|
59
|
+
"createAgent() does not yet support system prompt presets for this backend.",
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
system = options.systemPrompt;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const memoryBlocks: CreateAgentMemoryBlock[] = [];
|
|
66
|
+
const blockIds: string[] = [];
|
|
67
|
+
for (const item of options.memory ?? []) {
|
|
68
|
+
if (typeof item === "string") {
|
|
69
|
+
throw new Error(
|
|
70
|
+
"App-server createAgent() does not yet support memory preset names.",
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
if ("blockId" in item) {
|
|
74
|
+
blockIds.push(item.blockId);
|
|
75
|
+
} else {
|
|
76
|
+
memoryBlocks.push({ ...item });
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (options.persona !== undefined) {
|
|
80
|
+
memoryBlocks.push({ label: "persona", value: options.persona });
|
|
81
|
+
}
|
|
82
|
+
if (options.human !== undefined) {
|
|
83
|
+
memoryBlocks.push({ label: "human", value: options.human });
|
|
48
84
|
}
|
|
85
|
+
const hasMemoryConfiguration =
|
|
86
|
+
options.memory !== undefined ||
|
|
87
|
+
options.persona !== undefined ||
|
|
88
|
+
options.human !== undefined;
|
|
49
89
|
|
|
50
|
-
return {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
compaction_settings: { model: DEFAULT_SUMMARIZATION_MODEL },
|
|
65
|
-
};
|
|
90
|
+
return buildCreateAgentRequest({
|
|
91
|
+
personalityId: options.personality,
|
|
92
|
+
name: options.name,
|
|
93
|
+
description: options.description,
|
|
94
|
+
model: options.model,
|
|
95
|
+
system,
|
|
96
|
+
memoryBlocks: hasMemoryConfiguration ? memoryBlocks : undefined,
|
|
97
|
+
blockIds,
|
|
98
|
+
extraTags: options.tags,
|
|
99
|
+
enableMemfs: options.memfs ?? true,
|
|
100
|
+
baseTools: options.baseTools,
|
|
101
|
+
embedding: options.embedding,
|
|
102
|
+
hidden: options.hidden,
|
|
103
|
+
});
|
|
66
104
|
}
|
|
@@ -11,12 +11,7 @@ import type {
|
|
|
11
11
|
RuntimeStartResponseMessage,
|
|
12
12
|
UpdateModelResponseMessage,
|
|
13
13
|
} from "@letta-ai/letta-code/app-server-protocol";
|
|
14
|
-
import {
|
|
15
|
-
buildSystemPrompt,
|
|
16
|
-
GIT_MEMORY_ENABLED_TAG,
|
|
17
|
-
LETTA_CODE_ORIGIN_TAG,
|
|
18
|
-
} from "@letta-ai/letta-code/agent-presets";
|
|
19
|
-
import { buildInitialAgentBody } from "./agent-creation.js";
|
|
14
|
+
import { createAgentBody } from "./agent-creation.js";
|
|
20
15
|
import { normalizeAppServerModels } from "./app-server-models.js";
|
|
21
16
|
import {
|
|
22
17
|
buildCanUseToolContext,
|
|
@@ -99,152 +94,10 @@ export type AppServerSessionOptions = Partial<LettaCodeRemoteClientOptions> & {
|
|
|
99
94
|
connect?: (
|
|
100
95
|
sessionEnv?: Record<string, string>,
|
|
101
96
|
) => Promise<{ url: string; close(): void }>;
|
|
102
|
-
/** Whether SDK create-agent payloads should add the origin tag automatically. */
|
|
103
|
-
includeSdkOriginTag?: boolean;
|
|
104
97
|
};
|
|
105
98
|
|
|
106
99
|
export type AppServerSessionMode = RuntimeSessionMode;
|
|
107
100
|
|
|
108
|
-
function isPresetSystemPrompt(value: string): boolean {
|
|
109
|
-
return [
|
|
110
|
-
"default",
|
|
111
|
-
"letta-claude",
|
|
112
|
-
"letta-codex",
|
|
113
|
-
"letta-gemini",
|
|
114
|
-
"claude",
|
|
115
|
-
"codex",
|
|
116
|
-
"gemini",
|
|
117
|
-
].includes(value);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
function assertRemoteCreateAgentOptionsSupported(options: CreateAgentOptions): void {
|
|
121
|
-
if (options.allowedTools !== undefined || options.disallowedTools !== undefined) {
|
|
122
|
-
throw new Error("App-server createAgent() does not yet support allowedTools/disallowedTools.");
|
|
123
|
-
}
|
|
124
|
-
if (options.canUseTool !== undefined) {
|
|
125
|
-
throw new Error("App-server createAgent() does not yet support canUseTool callbacks.");
|
|
126
|
-
}
|
|
127
|
-
if (options.systemInfoReminder !== undefined) {
|
|
128
|
-
throw new Error("App-server createAgent() does not yet support systemInfoReminder overrides.");
|
|
129
|
-
}
|
|
130
|
-
if (options.dreaming?.behavior !== undefined) {
|
|
131
|
-
throw new Error("App-server createAgent() does not yet support dreaming.behavior overrides.");
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
function normalizeMemoryBlock(block: Record<string, unknown>): Record<string, unknown> {
|
|
136
|
-
const normalized = { ...block };
|
|
137
|
-
if (normalized.value === undefined && typeof normalized.content === "string") {
|
|
138
|
-
normalized.value = normalized.content;
|
|
139
|
-
}
|
|
140
|
-
return normalized;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
function upsertMemoryBlock(
|
|
144
|
-
blocks: Array<Record<string, unknown>>,
|
|
145
|
-
block: Record<string, unknown>,
|
|
146
|
-
): void {
|
|
147
|
-
const label = block.label;
|
|
148
|
-
if (typeof label === "string") {
|
|
149
|
-
const existingIndex = blocks.findIndex((candidate) => candidate.label === label);
|
|
150
|
-
if (existingIndex >= 0) {
|
|
151
|
-
blocks[existingIndex] = block;
|
|
152
|
-
return;
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
blocks.push(block);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
export async function createAgentBody(
|
|
159
|
-
options: CreateAgentOptions,
|
|
160
|
-
settings: { includeSdkOriginTag?: boolean } = {},
|
|
161
|
-
): Promise<Record<string, unknown>> {
|
|
162
|
-
assertRemoteCreateAgentOptionsSupported(options);
|
|
163
|
-
|
|
164
|
-
const includeOriginTag = settings.includeSdkOriginTag ?? true;
|
|
165
|
-
const body = await buildInitialAgentBody(options);
|
|
166
|
-
|
|
167
|
-
if (Array.isArray(body.tags)) {
|
|
168
|
-
body.tags = body.tags.filter(
|
|
169
|
-
(tag) =>
|
|
170
|
-
(includeOriginTag || tag !== LETTA_CODE_ORIGIN_TAG) &&
|
|
171
|
-
(options.memfs !== false || tag !== GIT_MEMORY_ENABLED_TAG),
|
|
172
|
-
);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
if (options.embedding !== undefined) body.embedding = options.embedding;
|
|
176
|
-
if (options.hidden !== undefined) body.hidden = options.hidden;
|
|
177
|
-
// When baseTools is omitted, the harness applies its created-agent
|
|
178
|
-
// defaults (web_search, fetch_webpage). An explicit list is pinned exactly:
|
|
179
|
-
// `tools` alone does not suppress the Letta agent type's defaults, so both
|
|
180
|
-
// default tool attachment and its default tool rules are disabled here.
|
|
181
|
-
if (options.baseTools === undefined) {
|
|
182
|
-
delete body.tools;
|
|
183
|
-
delete body.include_base_tools;
|
|
184
|
-
delete body.include_base_tool_rules;
|
|
185
|
-
} else {
|
|
186
|
-
body.tools = options.baseTools;
|
|
187
|
-
body.include_base_tools = false;
|
|
188
|
-
body.include_base_tool_rules = false;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
if (options.systemPrompt === undefined) {
|
|
192
|
-
if (options.memfs === false) {
|
|
193
|
-
body.system = buildSystemPrompt("default", "standard");
|
|
194
|
-
}
|
|
195
|
-
} else {
|
|
196
|
-
if (typeof options.systemPrompt === "string") {
|
|
197
|
-
if (isPresetSystemPrompt(options.systemPrompt)) {
|
|
198
|
-
throw new Error("createAgent() does not yet support system prompt presets for this backend.");
|
|
199
|
-
}
|
|
200
|
-
body.system = options.systemPrompt;
|
|
201
|
-
} else {
|
|
202
|
-
throw new Error("createAgent() does not yet support system prompt preset objects for this backend.");
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
const hasMemoryConfiguration =
|
|
207
|
-
Array.isArray(body.memory_blocks) ||
|
|
208
|
-
options.memory !== undefined ||
|
|
209
|
-
options.persona !== undefined ||
|
|
210
|
-
options.human !== undefined;
|
|
211
|
-
const memoryBlocks = Array.isArray(body.memory_blocks)
|
|
212
|
-
? body.memory_blocks
|
|
213
|
-
.filter(
|
|
214
|
-
(block): block is Record<string, unknown> =>
|
|
215
|
-
block !== null && typeof block === "object",
|
|
216
|
-
)
|
|
217
|
-
.map((block) => ({ ...block }))
|
|
218
|
-
: [];
|
|
219
|
-
const blockIds: string[] = [];
|
|
220
|
-
for (const item of options.memory ?? []) {
|
|
221
|
-
if (typeof item === "string") {
|
|
222
|
-
throw new Error("App-server createAgent() does not yet support memory preset names.");
|
|
223
|
-
}
|
|
224
|
-
if ("blockId" in item) {
|
|
225
|
-
blockIds.push(item.blockId);
|
|
226
|
-
} else {
|
|
227
|
-
upsertMemoryBlock(
|
|
228
|
-
memoryBlocks,
|
|
229
|
-
normalizeMemoryBlock(item as unknown as Record<string, unknown>),
|
|
230
|
-
);
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
if (options.persona !== undefined) {
|
|
234
|
-
upsertMemoryBlock(memoryBlocks, {
|
|
235
|
-
label: "persona",
|
|
236
|
-
value: options.persona,
|
|
237
|
-
});
|
|
238
|
-
}
|
|
239
|
-
if (options.human !== undefined) {
|
|
240
|
-
upsertMemoryBlock(memoryBlocks, { label: "human", value: options.human });
|
|
241
|
-
}
|
|
242
|
-
if (hasMemoryConfiguration) body.memory_blocks = memoryBlocks;
|
|
243
|
-
if (blockIds.length > 0) body.block_ids = blockIds;
|
|
244
|
-
|
|
245
|
-
return body;
|
|
246
|
-
}
|
|
247
|
-
|
|
248
101
|
export function externalToolGroups(tools: AnyAgentTool[] | undefined): Array<Record<string, unknown>> | undefined {
|
|
249
102
|
if (!tools || tools.length === 0) return undefined;
|
|
250
103
|
return [
|
|
@@ -779,6 +632,8 @@ export class AppServerSession extends RemoteClientSessionCore {
|
|
|
779
632
|
throw new Error(response.error ?? "Failed to start app-server runtime");
|
|
780
633
|
}
|
|
781
634
|
|
|
635
|
+
this.watchTransportDisconnect(client);
|
|
636
|
+
|
|
782
637
|
const tools = agentToolNames(response.agent);
|
|
783
638
|
const skillSources = options.skillSources;
|
|
784
639
|
const clientToolset = "toolset" in options ? options.toolset : undefined;
|
|
@@ -883,9 +738,7 @@ export class AppServerSession extends RemoteClientSessionCore {
|
|
|
883
738
|
|
|
884
739
|
if (this.mode.kind === "create-agent") {
|
|
885
740
|
command.create_agent = {
|
|
886
|
-
body: await createAgentBody(this.mode.options,
|
|
887
|
-
includeSdkOriginTag: this.remoteOptions.includeSdkOriginTag,
|
|
888
|
-
}),
|
|
741
|
+
body: await createAgentBody(this.mode.options),
|
|
889
742
|
// Hidden (worker-style) agents default to unpinned.
|
|
890
743
|
pin_global:
|
|
891
744
|
this.remoteOptions.pinGlobalAgent ??
|
package/src/cloud-session.ts
CHANGED
|
@@ -5,10 +5,10 @@ import {
|
|
|
5
5
|
createAppServerClient,
|
|
6
6
|
type AppServerClient,
|
|
7
7
|
} from "@letta-ai/letta-code/app-server-client";
|
|
8
|
+
import { createAgentBody } from "./agent-creation.js";
|
|
8
9
|
import {
|
|
9
10
|
AppServerRuntimeController,
|
|
10
11
|
agentToolNames,
|
|
11
|
-
createAgentBody,
|
|
12
12
|
createExternalToolCallHandler,
|
|
13
13
|
externalToolGroups,
|
|
14
14
|
registerAppServerControlRequestHandler,
|
|
@@ -398,6 +398,8 @@ export class CloudEnvironmentSession extends RemoteClientSessionCore {
|
|
|
398
398
|
throw new Error(response.error ?? "Failed to start Cloud status runtime");
|
|
399
399
|
}
|
|
400
400
|
|
|
401
|
+
this.watchTransportDisconnect(client);
|
|
402
|
+
|
|
401
403
|
const tools = agentToolNames(response.agent);
|
|
402
404
|
const skillSources = options.skillSources;
|
|
403
405
|
const clientToolset = "toolset" in options ? options.toolset : undefined;
|
|
@@ -77,6 +77,7 @@ export abstract class RemoteClientSessionCore implements LettaCodeSession {
|
|
|
77
77
|
private readonly requestTimeoutMs: number | undefined;
|
|
78
78
|
private initializePromise: Promise<SDKInitMessage> | null = null;
|
|
79
79
|
private removeMessageHandler: (() => void) | null = null;
|
|
80
|
+
private detachTransportDisconnect: (() => void) | null = null;
|
|
80
81
|
private readonly turns: RemoteTurnCoordinator;
|
|
81
82
|
private toolNames: string[] | undefined;
|
|
82
83
|
private deviceStatusListeners = new Set<(status: SessionDeviceStatus) => void>();
|
|
@@ -188,6 +189,8 @@ export abstract class RemoteClientSessionCore implements LettaCodeSession {
|
|
|
188
189
|
private cleanupFailedInitialize(): void {
|
|
189
190
|
this.removeMessageHandler?.();
|
|
190
191
|
this.removeMessageHandler = null;
|
|
192
|
+
this.detachTransportDisconnect?.();
|
|
193
|
+
this.detachTransportDisconnect = null;
|
|
191
194
|
this.controller?.close();
|
|
192
195
|
this.controller = null;
|
|
193
196
|
// Subclass-owned resources (spawned connections, sandboxes, handlers)
|
|
@@ -543,6 +546,8 @@ export abstract class RemoteClientSessionCore implements LettaCodeSession {
|
|
|
543
546
|
this.closed = true;
|
|
544
547
|
this.removeMessageHandler?.();
|
|
545
548
|
this.removeMessageHandler = null;
|
|
549
|
+
this.detachTransportDisconnect?.();
|
|
550
|
+
this.detachTransportDisconnect = null;
|
|
546
551
|
this.turns.close();
|
|
547
552
|
for (const cancel of [...this.deviceStatusRefreshCancels]) {
|
|
548
553
|
cancel(new Error(`Session closed while waiting for ${this.label} device status`));
|
|
@@ -619,6 +624,35 @@ export abstract class RemoteClientSessionCore implements LettaCodeSession {
|
|
|
619
624
|
|
|
620
625
|
protected abstract initializeRuntimeController(): Promise<RuntimeSessionInit>;
|
|
621
626
|
|
|
627
|
+
/**
|
|
628
|
+
* Fail the session when its transport drops unexpectedly.
|
|
629
|
+
*
|
|
630
|
+
* Without this an in-flight turn parks forever: nextMessage() only settles
|
|
631
|
+
* through the coordinator, and the socket's own pending-request rejection
|
|
632
|
+
* covers request/response commands, not streaming turns.
|
|
633
|
+
*
|
|
634
|
+
* The session is not revived — the runtime lived on the dead socket. The
|
|
635
|
+
* caller observes the error and rebuilds via resumeSession().
|
|
636
|
+
*
|
|
637
|
+
* Subclasses call this only once their runtime is live: a drop before that
|
|
638
|
+
* already surfaces as a rejected connect or runtime-start, and failing the
|
|
639
|
+
* session there would defeat initialize()'s retry path. Explicit closes do
|
|
640
|
+
* not notify, so this fires for faults only. Detaching stays here so every
|
|
641
|
+
* teardown path — clean close and failed initialize alike — covers it.
|
|
642
|
+
*/
|
|
643
|
+
protected watchTransportDisconnect(client: {
|
|
644
|
+
onDisconnect(handler: () => void): () => void;
|
|
645
|
+
}): void {
|
|
646
|
+
this.detachTransportDisconnect?.();
|
|
647
|
+
this.detachTransportDisconnect = client.onDisconnect(() => {
|
|
648
|
+
if (this.closed) return;
|
|
649
|
+
this.turns.closeWithError(
|
|
650
|
+
`The ${this.label} connection closed unexpectedly; resume the conversation to continue.`,
|
|
651
|
+
);
|
|
652
|
+
this.close();
|
|
653
|
+
});
|
|
654
|
+
}
|
|
655
|
+
|
|
622
656
|
protected async afterRuntimeInitialized(): Promise<void> {
|
|
623
657
|
// Optional hook for subclasses to send transport-specific startup frames.
|
|
624
658
|
}
|
|
@@ -160,6 +160,33 @@ export class RemoteTurnCoordinator {
|
|
|
160
160
|
});
|
|
161
161
|
}
|
|
162
162
|
|
|
163
|
+
/**
|
|
164
|
+
* Close after the transport dropped, surfacing the failure to stream
|
|
165
|
+
* consumers first.
|
|
166
|
+
*
|
|
167
|
+
* A plain close() resolves waiting consumers with `null`, which is
|
|
168
|
+
* indistinguishable from a conversation ending normally. A dead socket
|
|
169
|
+
* cannot deliver a turn-scoped failure of its own, so the error is
|
|
170
|
+
* synthesized here before the queue drains.
|
|
171
|
+
*/
|
|
172
|
+
closeWithError(detail: string): void {
|
|
173
|
+
if (this.closed) return;
|
|
174
|
+
const active = this.activeTurn;
|
|
175
|
+
if (active) {
|
|
176
|
+
this.failTurn(active, detail);
|
|
177
|
+
} else {
|
|
178
|
+
this.enqueue({
|
|
179
|
+
type: "error",
|
|
180
|
+
message: detail,
|
|
181
|
+
errorCode: "error",
|
|
182
|
+
stopReason: "error",
|
|
183
|
+
errorDetail: detail,
|
|
184
|
+
recoverable: false,
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
this.close();
|
|
188
|
+
}
|
|
189
|
+
|
|
163
190
|
close(): void {
|
|
164
191
|
if (this.closed) return;
|
|
165
192
|
this.closed = true;
|