tinker-agent 2.11.0 → 2.12.0
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/CHANGELOG.md +19 -1
- package/README.md +31 -67
- package/package.json +1 -1
- package/src/agent/runtime-session-contracts.ts +2 -29
- package/src/agent/runtime-session.ts +13 -67
- package/src/cli/config.ts +0 -29
- package/src/cli/model-profiles.ts +0 -80
- package/src/cli/public-config-contract.ts +1 -82
- package/src/cli/tui-runner.tsx +2 -41
- package/src/events/observation-text-log.ts +7 -0
- package/src/memory/contracts.ts +0 -256
- package/src/memory/memory-create-tool.ts +3 -5
- package/src/memory/memory-files.ts +145 -0
- package/src/memory/memory-search-output.ts +23 -0
- package/src/memory/memory-search-tool.ts +79 -175
- package/src/memory/memory-search.ts +115 -0
- package/src/observation/observation-builder.ts +5 -1
- package/src/session/session-store-contracts.ts +0 -23
- package/src/session/session-store.ts +2 -103
- package/src/tools/registry.ts +15 -18
- package/src/tools/types.ts +12 -0
- package/src/tui/app.tsx +6 -4
- package/src/tui/event-store.ts +3 -1
- package/src/cli/tui-memory.ts +0 -69
- package/src/memory/embedding-client.ts +0 -105
- package/src/memory/memory-coordinator.ts +0 -1274
- package/src/memory/memory-delete-tool.ts +0 -88
- package/src/memory/memory-extractor.ts +0 -252
- package/src/memory/memory-get-tool.ts +0 -86
- package/src/memory/memory-log.ts +0 -88
- package/src/memory/memory-store.ts +0 -1133
- package/src/memory/memory-update-tool.ts +0 -142
- package/src/memory/vector.ts +0 -153
package/src/tui/app.tsx
CHANGED
|
@@ -84,7 +84,9 @@ export type AppProps = {
|
|
|
84
84
|
writeClipboard?: (markdown: string) => Promise<void>;
|
|
85
85
|
onQuit?: () => void;
|
|
86
86
|
initialNotice?: string;
|
|
87
|
-
listStoredMemories?: () =>
|
|
87
|
+
listStoredMemories?: () =>
|
|
88
|
+
| readonly StoredMemorySummary[]
|
|
89
|
+
| Promise<readonly StoredMemorySummary[]>;
|
|
88
90
|
memoryDisabledNotice?: string;
|
|
89
91
|
};
|
|
90
92
|
|
|
@@ -418,13 +420,13 @@ export function App(props: AppProps) {
|
|
|
418
420
|
restoreStaticViewport();
|
|
419
421
|
};
|
|
420
422
|
|
|
421
|
-
const openMemoryView = () => {
|
|
423
|
+
const openMemoryView = async () => {
|
|
422
424
|
if (props.listStoredMemories === undefined) {
|
|
423
425
|
setNotice(props.memoryDisabledNotice ?? "memory disabled: not configured");
|
|
424
426
|
return;
|
|
425
427
|
}
|
|
426
428
|
try {
|
|
427
|
-
const snapshot = props.listStoredMemories();
|
|
429
|
+
const snapshot = await props.listStoredMemories();
|
|
428
430
|
setNotice(undefined);
|
|
429
431
|
setMemoryView(snapshot);
|
|
430
432
|
} catch (error) {
|
|
@@ -646,7 +648,7 @@ export function App(props: AppProps) {
|
|
|
646
648
|
return true;
|
|
647
649
|
}
|
|
648
650
|
if (command.type === "memory") {
|
|
649
|
-
openMemoryView();
|
|
651
|
+
void openMemoryView();
|
|
650
652
|
return true;
|
|
651
653
|
}
|
|
652
654
|
if (command.type === "copy") {
|
package/src/tui/event-store.ts
CHANGED
|
@@ -835,7 +835,7 @@ function toolCallSummary(input: { name: string; args: unknown }): string {
|
|
|
835
835
|
return `WebSearch ${toolQuery(input.args) ?? ""}`.trim();
|
|
836
836
|
}
|
|
837
837
|
if (input.name === "MemorySearch") {
|
|
838
|
-
return `MemorySearch ${memorySearchDetail(input.args)}`.trim();
|
|
838
|
+
return `MemorySearch ${toolPattern(input.args) ?? memorySearchDetail(input.args)}`.trim();
|
|
839
839
|
}
|
|
840
840
|
if (input.name === "MemoryCreate") {
|
|
841
841
|
return "MemoryCreate";
|
|
@@ -974,6 +974,8 @@ function toolRawResultSummary(name: string, args: unknown, raw: ToolRawResult):
|
|
|
974
974
|
if (!raw.ok) {
|
|
975
975
|
return base;
|
|
976
976
|
}
|
|
977
|
+
if ("format" in raw)
|
|
978
|
+
return `${base} -> ${raw.returnedResults} matching lines in ${raw.files.length} files`;
|
|
977
979
|
return `${base} -> ${raw.matches.length} derived memor${raw.matches.length === 1 ? "y" : "ies"}`;
|
|
978
980
|
case "memory_get":
|
|
979
981
|
if (!raw.ok) {
|
package/src/cli/tui-memory.ts
DELETED
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
boundedMemoryError,
|
|
3
|
-
memoryErrorCode,
|
|
4
|
-
type MemoryPaths,
|
|
5
|
-
} from "../memory/contracts";
|
|
6
|
-
import { MemoryCoordinator } from "../memory/memory-coordinator";
|
|
7
|
-
import { MemoryLog } from "../memory/memory-log";
|
|
8
|
-
import { resolveMemoryPaths } from "../memory/memory-store";
|
|
9
|
-
import type { ResolvedMemoryConfig } from "./config";
|
|
10
|
-
import { createModelClient } from "./runner-dependencies";
|
|
11
|
-
|
|
12
|
-
export type TuiMemoryInitialization = {
|
|
13
|
-
readonly coordinator?: MemoryCoordinator;
|
|
14
|
-
readonly notice?: string;
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
export async function initializeTuiMemory(input: {
|
|
18
|
-
readonly config?: ResolvedMemoryConfig;
|
|
19
|
-
readonly env: NodeJS.ProcessEnv;
|
|
20
|
-
readonly paths?: MemoryPaths;
|
|
21
|
-
readonly createCoordinator?: typeof MemoryCoordinator.create;
|
|
22
|
-
}): Promise<TuiMemoryInitialization> {
|
|
23
|
-
if (input.config === undefined) {
|
|
24
|
-
return Object.freeze({});
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const paths = input.paths ?? resolveMemoryPaths();
|
|
28
|
-
const log = new MemoryLog(paths.log);
|
|
29
|
-
try {
|
|
30
|
-
const memoryConfig = input.config;
|
|
31
|
-
const coordinator = await (input.createCoordinator ?? MemoryCoordinator.create)({
|
|
32
|
-
paths,
|
|
33
|
-
embedding: memoryConfig.embedding,
|
|
34
|
-
extractionContextBudget: memoryConfig.contextBudget,
|
|
35
|
-
createExtractionClient: () => {
|
|
36
|
-
const profile = memoryConfig.profile;
|
|
37
|
-
return createModelClient(
|
|
38
|
-
{
|
|
39
|
-
modelName: profile.model,
|
|
40
|
-
api: profile.api,
|
|
41
|
-
apiKey: profile.apiKey,
|
|
42
|
-
apiBase: profile.apiBase,
|
|
43
|
-
...(profile.reasoning === undefined
|
|
44
|
-
? {}
|
|
45
|
-
: { reasoning: profile.reasoning }),
|
|
46
|
-
includeReasoningContent: profile.includeReasoningContent,
|
|
47
|
-
stream: profile.stream,
|
|
48
|
-
contextBudget: memoryConfig.contextBudget,
|
|
49
|
-
inputModalities: profile.inputModalities,
|
|
50
|
-
toolResultModalities: profile.toolResultModalities,
|
|
51
|
-
},
|
|
52
|
-
input.env,
|
|
53
|
-
);
|
|
54
|
-
},
|
|
55
|
-
});
|
|
56
|
-
return Object.freeze({ coordinator });
|
|
57
|
-
} catch (error) {
|
|
58
|
-
const reason = memoryErrorCode(error, "memory_init_failed");
|
|
59
|
-
await log.append({
|
|
60
|
-
at: new Date().toISOString(),
|
|
61
|
-
kind: "init",
|
|
62
|
-
outcome: "failed",
|
|
63
|
-
reason,
|
|
64
|
-
});
|
|
65
|
-
return Object.freeze({
|
|
66
|
-
notice: `memory disabled: ${boundedMemoryError(error)}`,
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
}
|
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
import OpenAI from "openai";
|
|
2
|
-
import type { MemoryEmbeddingConfig } from "./contracts";
|
|
3
|
-
import { MemoryError } from "./contracts";
|
|
4
|
-
|
|
5
|
-
const EMBEDDING_TIMEOUT_MS = 60_000;
|
|
6
|
-
const EMBEDDING_MAX_RETRIES = 2;
|
|
7
|
-
|
|
8
|
-
export interface MemoryEmbeddingClient {
|
|
9
|
-
embed(
|
|
10
|
-
inputs: readonly string[],
|
|
11
|
-
signal: AbortSignal,
|
|
12
|
-
): Promise<readonly (readonly number[])[]>;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export class OpenAICompatibleEmbeddingClient implements MemoryEmbeddingClient {
|
|
16
|
-
private readonly client: OpenAI;
|
|
17
|
-
|
|
18
|
-
constructor(
|
|
19
|
-
private readonly config: MemoryEmbeddingConfig,
|
|
20
|
-
options: { readonly fetch?: typeof fetch } = {},
|
|
21
|
-
) {
|
|
22
|
-
this.client = new OpenAI({
|
|
23
|
-
apiKey: config.apiKey,
|
|
24
|
-
baseURL: config.apiBase,
|
|
25
|
-
timeout: EMBEDDING_TIMEOUT_MS,
|
|
26
|
-
maxRetries: EMBEDDING_MAX_RETRIES,
|
|
27
|
-
...(options.fetch === undefined ? {} : { fetch: options.fetch }),
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
async embed(
|
|
32
|
-
inputs: readonly string[],
|
|
33
|
-
signal: AbortSignal,
|
|
34
|
-
): Promise<readonly (readonly number[])[]> {
|
|
35
|
-
if (inputs.length === 0) {
|
|
36
|
-
throw new MemoryError(
|
|
37
|
-
"memory_embedding_input_invalid",
|
|
38
|
-
"Embedding input must not be empty.",
|
|
39
|
-
);
|
|
40
|
-
}
|
|
41
|
-
signal.throwIfAborted();
|
|
42
|
-
|
|
43
|
-
let response;
|
|
44
|
-
try {
|
|
45
|
-
response = await this.client.embeddings.create(
|
|
46
|
-
{
|
|
47
|
-
model: this.config.model,
|
|
48
|
-
input: [...inputs],
|
|
49
|
-
encoding_format: "float",
|
|
50
|
-
},
|
|
51
|
-
{ signal },
|
|
52
|
-
);
|
|
53
|
-
} catch (error) {
|
|
54
|
-
if (signal.aborted) {
|
|
55
|
-
throw error;
|
|
56
|
-
}
|
|
57
|
-
throw new MemoryError(
|
|
58
|
-
"memory_embedding_request_failed",
|
|
59
|
-
"Embedding provider request failed.",
|
|
60
|
-
{ cause: error },
|
|
61
|
-
);
|
|
62
|
-
}
|
|
63
|
-
signal.throwIfAborted();
|
|
64
|
-
|
|
65
|
-
if (!Array.isArray(response.data)) {
|
|
66
|
-
throw new MemoryError(
|
|
67
|
-
"memory_embedding_response_invalid",
|
|
68
|
-
"Embedding response did not contain a data array.",
|
|
69
|
-
);
|
|
70
|
-
}
|
|
71
|
-
if (response.data.length !== inputs.length) {
|
|
72
|
-
throw new MemoryError(
|
|
73
|
-
"memory_embedding_response_invalid",
|
|
74
|
-
`Embedding response returned ${response.data.length} vectors for ${inputs.length} inputs.`,
|
|
75
|
-
);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
const vectors: Array<readonly number[] | undefined> = Array.from({
|
|
79
|
-
length: inputs.length,
|
|
80
|
-
});
|
|
81
|
-
for (const item of response.data) {
|
|
82
|
-
if (
|
|
83
|
-
!Number.isSafeInteger(item.index) ||
|
|
84
|
-
item.index < 0 ||
|
|
85
|
-
item.index >= inputs.length ||
|
|
86
|
-
vectors[item.index] !== undefined ||
|
|
87
|
-
!Array.isArray(item.embedding) ||
|
|
88
|
-
item.embedding.some((value) => typeof value !== "number")
|
|
89
|
-
) {
|
|
90
|
-
throw new MemoryError(
|
|
91
|
-
"memory_embedding_response_invalid",
|
|
92
|
-
"Embedding response indices or vectors are invalid.",
|
|
93
|
-
);
|
|
94
|
-
}
|
|
95
|
-
vectors[item.index] = Object.freeze([...item.embedding]);
|
|
96
|
-
}
|
|
97
|
-
if (vectors.some((vector) => vector === undefined)) {
|
|
98
|
-
throw new MemoryError(
|
|
99
|
-
"memory_embedding_response_invalid",
|
|
100
|
-
"Embedding response did not map every input index.",
|
|
101
|
-
);
|
|
102
|
-
}
|
|
103
|
-
return Object.freeze(vectors as readonly (readonly number[])[]);
|
|
104
|
-
}
|
|
105
|
-
}
|