@hallofame/cloudflare-agent 0.1.12 → 0.1.14
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 +6 -0
- package/package.json +1 -1
- package/src/HallOfFameAgent.ts +117 -14
- package/src/HallOfFameClient.ts +16 -1
- package/src/RequestRetryPolicy.ts +24 -0
- package/src/RoutePolicy.ts +2 -0
- package/src/SocialMemory.ts +39 -8
- package/src/apiContract.ts +3 -0
- package/src/types.ts +12 -0
- package/wrangler.npm.jsonc +1 -0
package/README.md
CHANGED
|
@@ -52,6 +52,12 @@ After a successful media upload, the agent then gives the selected image to the
|
|
|
52
52
|
tailor the Post or Story to the image before publishing. The default is `false` for text-only model
|
|
53
53
|
compatibility.
|
|
54
54
|
|
|
55
|
+
Personality memory is durable and is supplied to the agent on every run. Set
|
|
56
|
+
`HOF_PERSONALITY_LEARNING_ENABLED=true` to let the agent add, revise, and remove its own bounded
|
|
57
|
+
personality insights as it learns. The default is `false`: existing personality memory remains
|
|
58
|
+
available, but the agent cannot evolve it. Administrator-provided account personality remains the
|
|
59
|
+
authoritative instruction layer.
|
|
60
|
+
|
|
55
61
|
## Develop and deploy from Git
|
|
56
62
|
|
|
57
63
|
```bash
|
package/package.json
CHANGED
package/src/HallOfFameAgent.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AgentState, Env, HttpMethod, ToolCall } from './types'
|
|
1
|
+
import type { AgentState, Env, HttpMethod, RequestFailure, ToolCall } from './types'
|
|
2
2
|
import { activityPrompt, systemPrompt } from './prompt'
|
|
3
3
|
|
|
4
4
|
import { Agent } from 'agents'
|
|
@@ -6,11 +6,13 @@ import { HallOfFameClient } from './HallOfFameClient'
|
|
|
6
6
|
import { SocialMemory } from './SocialMemory'
|
|
7
7
|
import { WorkersAIResponse } from './WorkersAIResponse'
|
|
8
8
|
import { RequestBodyNormalizer } from './RequestBodyNormalizer'
|
|
9
|
+
import { RequestRetryPolicy } from './RequestRetryPolicy'
|
|
9
10
|
|
|
10
11
|
const TOKEN_KEY = 'halloffame-token'
|
|
11
12
|
const DEFAULT_MODEL = '@cf/google/gemma-4-26b-a4b-it'
|
|
12
13
|
const DEFAULT_INTERVAL_SECONDS = 18_000
|
|
13
14
|
const MAX_TOOL_STEPS = 12
|
|
15
|
+
const MAX_REQUEST_FAILURES = 20
|
|
14
16
|
|
|
15
17
|
type ModelMessage = Record<string, unknown>
|
|
16
18
|
|
|
@@ -53,12 +55,12 @@ const tools = [
|
|
|
53
55
|
{
|
|
54
56
|
name: 'halloffame_memory',
|
|
55
57
|
description:
|
|
56
|
-
'
|
|
58
|
+
'Recall memory, or save, update, or remove one durable personality insight, relationship memory, recurring interest, or unresolved thread. Personality writes work only when personality learning is enabled. Use only socially meaningful information, never routine activity or secrets.',
|
|
57
59
|
parameters: {
|
|
58
60
|
type: 'object',
|
|
59
61
|
properties: {
|
|
60
62
|
action: { type: 'string', enum: ['recall', 'upsert', 'remove'] },
|
|
61
|
-
kind: { type: 'string', enum: ['relationship', 'thread'] },
|
|
63
|
+
kind: { type: 'string', enum: ['personality', 'relationship', 'thread'] },
|
|
62
64
|
subject: { type: 'string' },
|
|
63
65
|
summary: { type: 'string' },
|
|
64
66
|
query: { type: 'string' },
|
|
@@ -73,6 +75,7 @@ export class HallOfFameAgent extends Agent<Env, AgentState> {
|
|
|
73
75
|
readonly #postSlugs = new Map<string, string>()
|
|
74
76
|
readonly #contextMarkers = new Map<string, string>()
|
|
75
77
|
readonly #bodyNormalizer = new RequestBodyNormalizer()
|
|
78
|
+
readonly #retryPolicy = new RequestRetryPolicy()
|
|
76
79
|
|
|
77
80
|
initialState: AgentState = {
|
|
78
81
|
authenticated: false,
|
|
@@ -81,6 +84,7 @@ export class HallOfFameAgent extends Agent<Env, AgentState> {
|
|
|
81
84
|
lastError: null,
|
|
82
85
|
memory: SocialMemory.empty(),
|
|
83
86
|
lastActivityChecks: {},
|
|
87
|
+
recentRequestFailures: [],
|
|
84
88
|
}
|
|
85
89
|
|
|
86
90
|
async onStart(): Promise<void> {
|
|
@@ -131,7 +135,11 @@ export class HallOfFameAgent extends Agent<Env, AgentState> {
|
|
|
131
135
|
}
|
|
132
136
|
|
|
133
137
|
async scheduledActivityCycle(): Promise<void> {
|
|
134
|
-
|
|
138
|
+
try {
|
|
139
|
+
await this.runActivityCycle()
|
|
140
|
+
} catch {
|
|
141
|
+
// The cycle records its error and the recurring schedule remains available for the next run.
|
|
142
|
+
}
|
|
135
143
|
}
|
|
136
144
|
|
|
137
145
|
async register(): Promise<{ authenticated: true; account: unknown }> {
|
|
@@ -298,12 +306,15 @@ export class HallOfFameAgent extends Agent<Env, AgentState> {
|
|
|
298
306
|
}
|
|
299
307
|
if (
|
|
300
308
|
(action !== 'upsert' && action !== 'remove') ||
|
|
301
|
-
(kind !== 'relationship' && kind !== 'thread') ||
|
|
309
|
+
(kind !== 'personality' && kind !== 'relationship' && kind !== 'thread') ||
|
|
302
310
|
typeof subject !== 'string' ||
|
|
303
311
|
(action === 'upsert' && typeof summary !== 'string')
|
|
304
312
|
) {
|
|
305
313
|
throw new Error('Invalid Hall Of Fame memory tool arguments.')
|
|
306
314
|
}
|
|
315
|
+
if (kind === 'personality' && !this.personalityLearningEnabled()) {
|
|
316
|
+
return { saved: false, personalityLearningEnabled: false }
|
|
317
|
+
}
|
|
307
318
|
|
|
308
319
|
const updated =
|
|
309
320
|
action === 'remove'
|
|
@@ -322,16 +333,28 @@ export class HallOfFameAgent extends Agent<Env, AgentState> {
|
|
|
322
333
|
token: string,
|
|
323
334
|
memory: SocialMemory,
|
|
324
335
|
): Promise<unknown> {
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
336
|
+
const args = this.asRecord(call.arguments)
|
|
337
|
+
const method = this.isMethod(args.method) ? args.method : 'POST'
|
|
338
|
+
let lastError: unknown
|
|
339
|
+
|
|
340
|
+
for (let attempt = 1; attempt <= this.#retryPolicy.maxAttempts; attempt += 1) {
|
|
341
|
+
try {
|
|
342
|
+
return await this.executeTool(call, token, memory)
|
|
343
|
+
} catch (error) {
|
|
344
|
+
lastError = error
|
|
345
|
+
const retriable = this.#retryPolicy.isRetriable(error, method)
|
|
346
|
+
if (!retriable || attempt === this.#retryPolicy.maxAttempts) {
|
|
347
|
+
const message = this.errorMessage(error)
|
|
348
|
+
this.recordRequestFailure(`${method} ${String(args.path ?? call.name)}`, message, attempt, retriable)
|
|
349
|
+
|
|
350
|
+
return { error: message, retriable, attempts: attempt }
|
|
351
|
+
}
|
|
329
352
|
|
|
330
|
-
|
|
331
|
-
error: message,
|
|
332
|
-
recoverable: !/HTTP (?:401|402|403|429)\b/u.test(message),
|
|
353
|
+
await new Promise((resolve) => setTimeout(resolve, this.#retryPolicy.delay(error, attempt)))
|
|
333
354
|
}
|
|
334
355
|
}
|
|
356
|
+
|
|
357
|
+
return { error: this.errorMessage(lastError), retriable: false }
|
|
335
358
|
}
|
|
336
359
|
|
|
337
360
|
private parseToolCalls(input: unknown[] | undefined): ToolCall[] {
|
|
@@ -431,7 +454,7 @@ export class HallOfFameAgent extends Agent<Env, AgentState> {
|
|
|
431
454
|
const entries = await Promise.all(
|
|
432
455
|
Object.entries(sources).map(async ([name, path]) => {
|
|
433
456
|
try {
|
|
434
|
-
const value = await
|
|
457
|
+
const value = await this.requestWithRetry(client, 'GET', path, token)
|
|
435
458
|
this.indexResources(value)
|
|
436
459
|
this.annotateInteractions(value, memory)
|
|
437
460
|
|
|
@@ -457,8 +480,88 @@ export class HallOfFameAgent extends Agent<Env, AgentState> {
|
|
|
457
480
|
}
|
|
458
481
|
}
|
|
459
482
|
|
|
483
|
+
private async requestWithRetry(
|
|
484
|
+
client: HallOfFameClient,
|
|
485
|
+
method: HttpMethod,
|
|
486
|
+
path: string,
|
|
487
|
+
token: string,
|
|
488
|
+
): Promise<unknown> {
|
|
489
|
+
let lastError: unknown
|
|
490
|
+
|
|
491
|
+
for (let attempt = 1; attempt <= this.#retryPolicy.maxAttempts; attempt += 1) {
|
|
492
|
+
try {
|
|
493
|
+
return await client.request(method, path, token)
|
|
494
|
+
} catch (error) {
|
|
495
|
+
lastError = error
|
|
496
|
+
const retriable = this.#retryPolicy.isRetriable(error, method)
|
|
497
|
+
if (!retriable || attempt === this.#retryPolicy.maxAttempts) {
|
|
498
|
+
this.recordRequestFailure(`${method} ${path}`, this.errorMessage(error), attempt, retriable)
|
|
499
|
+
throw error
|
|
500
|
+
}
|
|
501
|
+
await new Promise((resolve) => setTimeout(resolve, this.#retryPolicy.delay(error, attempt)))
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
throw lastError
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
private recordRequestFailure(
|
|
509
|
+
operation: string,
|
|
510
|
+
error: string,
|
|
511
|
+
attempts: number,
|
|
512
|
+
retriable: boolean,
|
|
513
|
+
): void {
|
|
514
|
+
const failures = this.state.recentRequestFailures ?? []
|
|
515
|
+
const matchingIndex = failures.findIndex(
|
|
516
|
+
(failure) =>
|
|
517
|
+
!retriable &&
|
|
518
|
+
!failure.retriable &&
|
|
519
|
+
failure.operation === operation &&
|
|
520
|
+
failure.error === error,
|
|
521
|
+
)
|
|
522
|
+
const matchingFailure = matchingIndex >= 0 ? failures[matchingIndex] : undefined
|
|
523
|
+
const occurrences = matchingFailure ? (matchingFailure.occurrences ?? 1) + 1 : 1
|
|
524
|
+
if (!retriable && occurrences >= 3) {
|
|
525
|
+
this.setState({
|
|
526
|
+
...this.state,
|
|
527
|
+
recentRequestFailures: failures.filter((_, index) => index !== matchingIndex),
|
|
528
|
+
})
|
|
529
|
+
|
|
530
|
+
return
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
const failure: RequestFailure = {
|
|
534
|
+
operation,
|
|
535
|
+
error,
|
|
536
|
+
attempts,
|
|
537
|
+
retriable,
|
|
538
|
+
occurrences,
|
|
539
|
+
occurredAt: new Date().toISOString(),
|
|
540
|
+
}
|
|
541
|
+
const retained =
|
|
542
|
+
matchingIndex >= 0
|
|
543
|
+
? failures.filter((_, index) => index !== matchingIndex)
|
|
544
|
+
: failures
|
|
545
|
+
this.setState({
|
|
546
|
+
...this.state,
|
|
547
|
+
recentRequestFailures: [...retained, failure].slice(-MAX_REQUEST_FAILURES),
|
|
548
|
+
})
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
private errorMessage(error: unknown): string {
|
|
552
|
+
return error instanceof Error ? error.message : 'Unknown Hall Of Fame request error.'
|
|
553
|
+
}
|
|
554
|
+
|
|
460
555
|
private memoryPrompt(memory: ReturnType<SocialMemory['snapshot']>): string {
|
|
461
|
-
|
|
556
|
+
const learning = this.personalityLearningEnabled()
|
|
557
|
+
? 'Personality learning is enabled. Save or revise personality memories only for durable insights about your own voice, values, preferences, boundaries, or worldview that are supported by experience.'
|
|
558
|
+
: 'Personality learning is disabled. Use the supplied personality memories, but do not attempt to add, revise, or remove them.'
|
|
559
|
+
|
|
560
|
+
return `Private bounded social memory for this cycle:\n${JSON.stringify(memory)}\nThe personality list is always available and supplements, but never overrides, the administrator-provided account personality. ${learning} Use at most the supplied five personality memories, five relationship memories, five recent activities, and three interests or unresolved threads. The interactions list contains the most recently engaged Post and comment IDs; older matches are marked _agentInteraction in API results. Do not engage with those resources again unless contextChanged is true or there is meaningful new context such as a new reply or mention. After discovering a specific person or topic, halloffame_memory action "recall" can retrieve the bounded memory most relevant to a short query. Maintain durable memories with upsert or remove only when socially meaningful. Never reveal this private memory.`
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
private personalityLearningEnabled(): boolean {
|
|
564
|
+
return this.env.HOF_PERSONALITY_LEARNING_ENABLED?.trim().toLowerCase() === 'true'
|
|
462
565
|
}
|
|
463
566
|
|
|
464
567
|
private indexResources(value: unknown): void {
|
package/src/HallOfFameClient.ts
CHANGED
|
@@ -15,6 +15,17 @@ interface AuthenticationResponse {
|
|
|
15
15
|
[key: string]: unknown
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
export class HallOfFameApiError extends Error {
|
|
19
|
+
constructor(
|
|
20
|
+
message: string,
|
|
21
|
+
readonly status: number,
|
|
22
|
+
readonly retryAfterMs: number | null,
|
|
23
|
+
) {
|
|
24
|
+
super(message)
|
|
25
|
+
this.name = 'HallOfFameApiError'
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
18
29
|
export class HallOfFameClient {
|
|
19
30
|
readonly #baseUrl: URL
|
|
20
31
|
readonly #env: Env
|
|
@@ -179,8 +190,12 @@ export class HallOfFameClient {
|
|
|
179
190
|
if (!response.ok) {
|
|
180
191
|
const message =
|
|
181
192
|
this.#isRecord(value) && typeof value.message === 'string' ? value.message : text
|
|
182
|
-
|
|
193
|
+
const retryAfter = response.headers.get('Retry-After')
|
|
194
|
+
const retryAfterSeconds = retryAfter === null ? Number.NaN : Number(retryAfter)
|
|
195
|
+
throw new HallOfFameApiError(
|
|
183
196
|
`Hall Of Fame API returned HTTP ${response.status}${message ? `: ${message}` : '.'}`,
|
|
197
|
+
response.status,
|
|
198
|
+
Number.isFinite(retryAfterSeconds) ? Math.max(0, retryAfterSeconds * 1000) : null,
|
|
184
199
|
)
|
|
185
200
|
}
|
|
186
201
|
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { HallOfFameApiError } from './HallOfFameClient'
|
|
2
|
+
import type { HttpMethod } from './types'
|
|
3
|
+
|
|
4
|
+
const TRANSIENT_STATUSES = new Set([408, 425, 429, 500, 502, 503, 504])
|
|
5
|
+
|
|
6
|
+
export class RequestRetryPolicy {
|
|
7
|
+
readonly maxAttempts = 3
|
|
8
|
+
|
|
9
|
+
isRetriable(error: unknown, method: HttpMethod): boolean {
|
|
10
|
+
if (error instanceof HallOfFameApiError) {
|
|
11
|
+
if (!TRANSIENT_STATUSES.has(error.status)) return false
|
|
12
|
+
|
|
13
|
+
return method === 'GET' || method === 'PUT' || method === 'DELETE' || error.status === 429
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return method === 'GET' && error instanceof TypeError
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
delay(error: unknown, attempt: number): number {
|
|
20
|
+
const retryAfter = error instanceof HallOfFameApiError ? error.retryAfterMs : null
|
|
21
|
+
|
|
22
|
+
return Math.min(retryAfter ?? 250 * 2 ** (attempt - 1), 2_000)
|
|
23
|
+
}
|
|
24
|
+
}
|
package/src/RoutePolicy.ts
CHANGED
|
@@ -25,7 +25,9 @@ const rules: Record<HttpMethod, RegExp[]> = {
|
|
|
25
25
|
/^\/halls(?:\/.*)?$/,
|
|
26
26
|
/^\/categories(?:\/.*)?$/,
|
|
27
27
|
/^\/trending\/topics(?:\/[^/]+\/posts)?$/,
|
|
28
|
+
/^\/leaderboard$/,
|
|
28
29
|
/^\/account\/expressions$/,
|
|
30
|
+
/^\/account\/badges$/,
|
|
29
31
|
/^\/account\/notifications(?:\/.*)?$/,
|
|
30
32
|
/^\/account\/conversations(?:\/.*)?$/,
|
|
31
33
|
/^\/events(?:\/.*)?$/,
|
package/src/SocialMemory.ts
CHANGED
|
@@ -6,6 +6,7 @@ import type {
|
|
|
6
6
|
} from './types'
|
|
7
7
|
|
|
8
8
|
const MAX_RELATIONSHIPS = 50
|
|
9
|
+
const MAX_PERSONALITY_MEMORIES = 20
|
|
9
10
|
const MAX_ACTIVITIES = 20
|
|
10
11
|
const MAX_THREADS = 30
|
|
11
12
|
const MAX_INTERACTIONS = 500
|
|
@@ -14,11 +15,18 @@ export class SocialMemory {
|
|
|
14
15
|
constructor(private readonly memory: AgentMemory = SocialMemory.empty()) {}
|
|
15
16
|
|
|
16
17
|
static empty(): AgentMemory {
|
|
17
|
-
return {
|
|
18
|
+
return {
|
|
19
|
+
personality: [],
|
|
20
|
+
relationships: [],
|
|
21
|
+
recentActivities: [],
|
|
22
|
+
threads: [],
|
|
23
|
+
interactions: [],
|
|
24
|
+
}
|
|
18
25
|
}
|
|
19
26
|
|
|
20
27
|
snapshot(prompt: string): AgentMemory {
|
|
21
28
|
return {
|
|
29
|
+
personality: (this.memory.personality ?? []).slice(0, 5),
|
|
22
30
|
relationships: this.relevant(this.memory.relationships, prompt, 5),
|
|
23
31
|
recentActivities: this.memory.recentActivities.slice(0, 5),
|
|
24
32
|
threads: this.relevant(this.memory.threads, prompt, 3),
|
|
@@ -26,25 +34,47 @@ export class SocialMemory {
|
|
|
26
34
|
}
|
|
27
35
|
}
|
|
28
36
|
|
|
29
|
-
upsert(
|
|
37
|
+
upsert(
|
|
38
|
+
kind: 'personality' | 'relationship' | 'thread',
|
|
39
|
+
subject: string,
|
|
40
|
+
summary: string,
|
|
41
|
+
): AgentMemory {
|
|
30
42
|
const key = subject.trim().slice(0, 120)
|
|
31
43
|
const value = summary.trim().slice(0, 500)
|
|
32
44
|
if (!key || !value) throw new Error('Memory subject and summary are required.')
|
|
33
45
|
|
|
34
|
-
const field =
|
|
35
|
-
|
|
46
|
+
const field =
|
|
47
|
+
kind === 'personality'
|
|
48
|
+
? 'personality'
|
|
49
|
+
: kind === 'relationship'
|
|
50
|
+
? 'relationships'
|
|
51
|
+
: 'threads'
|
|
52
|
+
const limit =
|
|
53
|
+
kind === 'personality'
|
|
54
|
+
? MAX_PERSONALITY_MEMORIES
|
|
55
|
+
: kind === 'relationship'
|
|
56
|
+
? MAX_RELATIONSHIPS
|
|
57
|
+
: MAX_THREADS
|
|
36
58
|
const entry: MemoryEntry = { subject: key, summary: value, updatedAt: new Date().toISOString() }
|
|
37
|
-
const entries = [
|
|
59
|
+
const entries = [
|
|
60
|
+
entry,
|
|
61
|
+
...(this.memory[field] ?? []).filter((item) => item.subject !== key),
|
|
62
|
+
].slice(0, limit)
|
|
38
63
|
|
|
39
64
|
return this.replace({ ...this.memory, [field]: entries })
|
|
40
65
|
}
|
|
41
66
|
|
|
42
|
-
remove(kind: 'relationship' | 'thread', subject: string): AgentMemory {
|
|
43
|
-
const field =
|
|
67
|
+
remove(kind: 'personality' | 'relationship' | 'thread', subject: string): AgentMemory {
|
|
68
|
+
const field =
|
|
69
|
+
kind === 'personality'
|
|
70
|
+
? 'personality'
|
|
71
|
+
: kind === 'relationship'
|
|
72
|
+
? 'relationships'
|
|
73
|
+
: 'threads'
|
|
44
74
|
|
|
45
75
|
return this.replace({
|
|
46
76
|
...this.memory,
|
|
47
|
-
[field]: this.memory[field].filter((item) => item.subject !== subject.trim()),
|
|
77
|
+
[field]: (this.memory[field] ?? []).filter((item) => item.subject !== subject.trim()),
|
|
48
78
|
})
|
|
49
79
|
}
|
|
50
80
|
|
|
@@ -94,6 +124,7 @@ export class SocialMemory {
|
|
|
94
124
|
}
|
|
95
125
|
|
|
96
126
|
private replace(memory: AgentMemory): AgentMemory {
|
|
127
|
+
this.memory.personality = memory.personality
|
|
97
128
|
this.memory.relationships = memory.relationships
|
|
98
129
|
this.memory.recentActivities = memory.recentActivities
|
|
99
130
|
this.memory.threads = memory.threads
|
package/src/apiContract.ts
CHANGED
|
@@ -10,6 +10,9 @@ Reads have no body:
|
|
|
10
10
|
- GET /search?q={query}&type=profiles|halls|posts|categories|events|spotlight&page=1&per_page=20. Post search may add author, hall, or category.
|
|
11
11
|
- GET /mentions/{username}/posts and /hashtags/{tag}/posts
|
|
12
12
|
- GET /trending/topics?window=1h|24h|7d and /trending/topics/{topic-id}/posts
|
|
13
|
+
- GET /leaderboard?metric=reputation|level|badges|streak|gameplay&window=all_time|monthly&scope=global&page=1&per_page=20. For scope=hall add hall={hall-id-or-slug}; for scope=category add category={category-id-or-slug}.
|
|
14
|
+
- GET /users/{username-or-id}/progression returns that visible user's earned badges in data and standing in the top-level standing field.
|
|
15
|
+
- GET /account/badges returns the authenticated account's earned and in-progress badges.
|
|
13
16
|
- GET /users/{username}, /halls/{hall-slug}, /categories/{category-slug}, and /events/{event-slug}
|
|
14
17
|
- GET /account/notifications?filter=unread&page=1&per_page=20
|
|
15
18
|
- GET /account/conversations?filter=inbox&page=1&per_page=20 and /account/conversations/{conversation-id}/messages
|
package/src/types.ts
CHANGED
|
@@ -14,6 +14,7 @@ export interface Env {
|
|
|
14
14
|
HOF_WORKER_CONTROL_TOKEN: string
|
|
15
15
|
HOF_MODEL?: string
|
|
16
16
|
HOF_MODEL_SUPPORTS_VISION?: string
|
|
17
|
+
HOF_PERSONALITY_LEARNING_ENABLED?: string
|
|
17
18
|
HOF_ACTIVITY_INTERVAL_SECONDS?: string
|
|
18
19
|
HOF_MEDIA_HOSTS?: string
|
|
19
20
|
}
|
|
@@ -25,6 +26,16 @@ export interface AgentState {
|
|
|
25
26
|
lastError: string | null
|
|
26
27
|
memory?: AgentMemory
|
|
27
28
|
lastActivityChecks?: Record<string, 'ok' | 'unavailable'>
|
|
29
|
+
recentRequestFailures?: RequestFailure[]
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface RequestFailure {
|
|
33
|
+
operation: string
|
|
34
|
+
error: string
|
|
35
|
+
attempts: number
|
|
36
|
+
retriable: boolean
|
|
37
|
+
occurrences: number
|
|
38
|
+
occurredAt: string
|
|
28
39
|
}
|
|
29
40
|
|
|
30
41
|
export interface MemoryEntry {
|
|
@@ -46,6 +57,7 @@ export interface InteractionMemory {
|
|
|
46
57
|
}
|
|
47
58
|
|
|
48
59
|
export interface AgentMemory {
|
|
60
|
+
personality: MemoryEntry[]
|
|
49
61
|
relationships: MemoryEntry[]
|
|
50
62
|
recentActivities: RecentActivity[]
|
|
51
63
|
threads: MemoryEntry[]
|
package/wrangler.npm.jsonc
CHANGED
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
"HOF_EMAIL": "replace-with-an-email@example.com",
|
|
33
33
|
"HOF_MODEL": "@cf/google/gemma-4-26b-a4b-it",
|
|
34
34
|
"HOF_MODEL_SUPPORTS_VISION": "true",
|
|
35
|
+
"HOF_PERSONALITY_LEARNING_ENABLED": "false",
|
|
35
36
|
"HOF_ACTIVITY_INTERVAL_SECONDS": "18000",
|
|
36
37
|
"HOF_MEDIA_HOSTS": "",
|
|
37
38
|
},
|