@josharsh/demon 0.1.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.
Files changed (51) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +35 -0
  3. package/dist/actions/portable.d.ts +4 -0
  4. package/dist/actions/portable.d.ts.map +1 -0
  5. package/dist/actions/portable.js +40 -0
  6. package/dist/actions/portable.js.map +1 -0
  7. package/dist/index.d.ts +17 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +26 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/llm/providers.d.ts +4 -0
  12. package/dist/llm/providers.d.ts.map +1 -0
  13. package/dist/llm/providers.js +163 -0
  14. package/dist/llm/providers.js.map +1 -0
  15. package/dist/loop.d.ts +16 -0
  16. package/dist/loop.d.ts.map +1 -0
  17. package/dist/loop.js +142 -0
  18. package/dist/loop.js.map +1 -0
  19. package/dist/memory/episodes.d.ts +12 -0
  20. package/dist/memory/episodes.d.ts.map +1 -0
  21. package/dist/memory/episodes.js +50 -0
  22. package/dist/memory/episodes.js.map +1 -0
  23. package/dist/memory/facts.d.ts +3 -0
  24. package/dist/memory/facts.d.ts.map +1 -0
  25. package/dist/memory/facts.js +98 -0
  26. package/dist/memory/facts.js.map +1 -0
  27. package/dist/memory/manager.d.ts +14 -0
  28. package/dist/memory/manager.d.ts.map +1 -0
  29. package/dist/memory/manager.js +113 -0
  30. package/dist/memory/manager.js.map +1 -0
  31. package/dist/memory/narrative.d.ts +8 -0
  32. package/dist/memory/narrative.d.ts.map +1 -0
  33. package/dist/memory/narrative.js +37 -0
  34. package/dist/memory/narrative.js.map +1 -0
  35. package/dist/platform/memory-kv.d.ts +3 -0
  36. package/dist/platform/memory-kv.d.ts.map +1 -0
  37. package/dist/platform/memory-kv.js +24 -0
  38. package/dist/platform/memory-kv.js.map +1 -0
  39. package/dist/reasoning.d.ts +22 -0
  40. package/dist/reasoning.d.ts.map +1 -0
  41. package/dist/reasoning.js +104 -0
  42. package/dist/reasoning.js.map +1 -0
  43. package/dist/types.d.ts +144 -0
  44. package/dist/types.d.ts.map +1 -0
  45. package/dist/types.js +9 -0
  46. package/dist/types.js.map +1 -0
  47. package/dist/util/time.d.ts +9 -0
  48. package/dist/util/time.d.ts.map +1 -0
  49. package/dist/util/time.js +38 -0
  50. package/dist/util/time.js.map +1 -0
  51. package/package.json +39 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Harsh
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,35 @@
1
+ # @josharsh/demon
2
+
3
+ The portable engine behind [demon](https://demon.josharsh.com) — a persistent reasoning process that watches a domain and acts on its own judgment, instead of waiting to be called.
4
+
5
+ This package is the platform-neutral core: the judgment loop, three-layer memory (event log + bi-temporal facts + compressed narrative), reasoning, and a fetch-based LLM layer. No native dependencies — it runs in Node, the browser, and at the edge. Host packages supply the `Clock` / `Logger` / `Storage` implementations via the platform seam.
6
+
7
+ If you just want to run demons, install the CLI instead:
8
+
9
+ ```bash
10
+ npm install -g @josharsh/demon-cli
11
+ ```
12
+
13
+ ## Embed the engine
14
+
15
+ ```bash
16
+ npm install @josharsh/demon
17
+ ```
18
+
19
+ ```ts
20
+ import { runLoop, createLLMProvider, createMemoryKV } from '@josharsh/demon'
21
+
22
+ await runLoop({
23
+ manifest, // name, purpose, watch, interval, actions, model, action_mode
24
+ watchers, // your Watcher[] — observe a domain
25
+ llm: createLLMProvider('claude-sonnet-4-6', { ANTHROPIC_API_KEY: key }),
26
+ actions, // Map<string, ActionProvider>
27
+ credentials: new Map(),
28
+ logger, clock, // inject your platform's Logger + Clock
29
+ storage: createMemoryKV(), // or a durable KVStore (fs / IndexedDB)
30
+ })
31
+ ```
32
+
33
+ You bring the watchers, actions, storage, and clock; the engine runs the observe → judge → act loop and keeps the memory.
34
+
35
+ MIT licensed. See the [main repo](https://github.com/josharsh/demon) for docs, the CLI, and the concept (agents vs demons).
@@ -0,0 +1,4 @@
1
+ import { ActionProvider, Logger } from '../types.js';
2
+ export declare function createLogAction(logger: Logger): ActionProvider;
3
+ export declare function createWebhookAction(): ActionProvider;
4
+ //# sourceMappingURL=portable.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"portable.d.ts","sourceRoot":"","sources":["../../src/actions/portable.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAqB,MAAM,EAAE,MAAM,aAAa,CAAA;AASvE,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,CAW9D;AAGD,wBAAgB,mBAAmB,IAAI,cAAc,CAkBpD"}
@@ -0,0 +1,40 @@
1
+ // ============================================================================
2
+ // Portable action providers — work in any runtime (Node + browser).
3
+ // Node-only actions (notify/osascript, file/fs, script/child_process) live in
4
+ // the host package. These cover the universal building blocks.
5
+ // ============================================================================
6
+ // `log` — write to the demon's logger. Always available, no credentials.
7
+ export function createLogAction(logger) {
8
+ return {
9
+ provider: 'log',
10
+ getAvailableActions: () => ['info', 'warn', 'error'],
11
+ async execute(instruction) {
12
+ const msg = String(instruction.params.message ?? instruction.params.text ?? '');
13
+ const level = instruction.action === 'warn' ? 'warn' : instruction.action === 'error' ? 'error' : 'info';
14
+ logger[level](`[demon-action] ${msg}`);
15
+ return { logged: true, level };
16
+ },
17
+ };
18
+ }
19
+ // `webhook` — POST JSON to any URL. The universal escape hatch.
20
+ export function createWebhookAction() {
21
+ return {
22
+ provider: 'webhook',
23
+ getAvailableActions: () => ['post'],
24
+ async execute(instruction) {
25
+ const url = String(instruction.params.url ?? '');
26
+ if (!url)
27
+ throw new Error('webhook.post requires a "url" param');
28
+ const method = String(instruction.params.method ?? 'POST');
29
+ const headers = {
30
+ 'content-type': 'application/json',
31
+ 'user-agent': 'demon/0.1',
32
+ ...instruction.params.headers,
33
+ };
34
+ const body = instruction.params.body ?? { from: 'demon', params: instruction.params };
35
+ const res = await fetch(url, { method, headers, body: JSON.stringify(body) });
36
+ return { status: res.status, ok: res.ok };
37
+ },
38
+ };
39
+ }
40
+ //# sourceMappingURL=portable.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"portable.js","sourceRoot":"","sources":["../../src/actions/portable.ts"],"names":[],"mappings":"AAEA,+EAA+E;AAC/E,oEAAoE;AACpE,8EAA8E;AAC9E,+DAA+D;AAC/D,+EAA+E;AAE/E,yEAAyE;AACzE,MAAM,UAAU,eAAe,CAAC,MAAc;IAC5C,OAAO;QACL,QAAQ,EAAE,KAAK;QACf,mBAAmB,EAAE,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC;QACpD,KAAK,CAAC,OAAO,CAAC,WAA8B;YAC1C,MAAM,GAAG,GAAG,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,IAAI,WAAW,CAAC,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC,CAAA;YAC/E,MAAM,KAAK,GAAG,WAAW,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAA;YACxG,MAAM,CAAC,KAAK,CAAC,CAAC,kBAAkB,GAAG,EAAE,CAAC,CAAA;YACtC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,CAAA;QAChC,CAAC;KACF,CAAA;AACH,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,mBAAmB;IACjC,OAAO;QACL,QAAQ,EAAE,SAAS;QACnB,mBAAmB,EAAE,GAAG,EAAE,CAAC,CAAC,MAAM,CAAC;QACnC,KAAK,CAAC,OAAO,CAAC,WAA8B;YAC1C,MAAM,GAAG,GAAG,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,GAAG,IAAI,EAAE,CAAC,CAAA;YAChD,IAAI,CAAC,GAAG;gBAAE,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAA;YAChE,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,CAAA;YAC1D,MAAM,OAAO,GAAG;gBACd,cAAc,EAAE,kBAAkB;gBAClC,YAAY,EAAE,WAAW;gBACzB,GAAI,WAAW,CAAC,MAAM,CAAC,OAA8C;aACtE,CAAA;YACD,MAAM,IAAI,GAAG,WAAW,CAAC,MAAM,CAAC,IAAI,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,CAAA;YACrF,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;YAC7E,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,CAAA;QAC3C,CAAC;KACF,CAAA;AACH,CAAC"}
@@ -0,0 +1,17 @@
1
+ export * from './types.js';
2
+ export { parseInterval, formatInterval } from './util/time.js';
3
+ export { buildDemonPrompt, splitPrompt, parseLLMDecision } from './reasoning.js';
4
+ export { createMemoryManager, extractFacts } from './memory/manager.js';
5
+ export type { MemoryManager, MemoryContext } from './memory/manager.js';
6
+ export { createFactsStore } from './memory/facts.js';
7
+ export { createEpisodeStore } from './memory/episodes.js';
8
+ export type { EpisodeStore } from './memory/episodes.js';
9
+ export { createNarrativeManager } from './memory/narrative.js';
10
+ export type { NarrativeManager } from './memory/narrative.js';
11
+ export { createLLMProvider } from './llm/providers.js';
12
+ export type { KeyMap } from './llm/providers.js';
13
+ export { runLoop } from './loop.js';
14
+ export type { LoopConfig } from './loop.js';
15
+ export { createLogAction, createWebhookAction } from './actions/portable.js';
16
+ export { createMemoryKV } from './platform/memory-kv.js';
17
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AASA,cAAc,YAAY,CAAA;AAG1B,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAC9D,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AAGhF,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AACvE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACvE,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AACzD,YAAY,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AACxD,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAA;AAC9D,YAAY,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AAG7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AACtD,YAAY,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAA;AAGhD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,YAAY,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAG3C,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAA;AAG5E,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,26 @@
1
+ // ============================================================================
2
+ // @josharsh/demon — the portable demon engine.
3
+ //
4
+ // A demon is a persistent reasoning process with a purpose: it observes,
5
+ // judges, and acts on its own — it is not invoked like an agent. This package
6
+ // is the platform-neutral core. Host packages (CLI, browser) supply the
7
+ // Clock / Logger / Storage implementations via the platform seam in types.ts.
8
+ // ============================================================================
9
+ export * from './types.js';
10
+ // reasoning
11
+ export { parseInterval, formatInterval } from './util/time.js';
12
+ export { buildDemonPrompt, splitPrompt, parseLLMDecision } from './reasoning.js';
13
+ // memory
14
+ export { createMemoryManager, extractFacts } from './memory/manager.js';
15
+ export { createFactsStore } from './memory/facts.js';
16
+ export { createEpisodeStore } from './memory/episodes.js';
17
+ export { createNarrativeManager } from './memory/narrative.js';
18
+ // llm
19
+ export { createLLMProvider } from './llm/providers.js';
20
+ // loop
21
+ export { runLoop } from './loop.js';
22
+ // portable actions
23
+ export { createLogAction, createWebhookAction } from './actions/portable.js';
24
+ // platform helpers
25
+ export { createMemoryKV } from './platform/memory-kv.js';
26
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,+CAA+C;AAC/C,EAAE;AACF,yEAAyE;AACzE,8EAA8E;AAC9E,wEAAwE;AACxE,8EAA8E;AAC9E,+EAA+E;AAE/E,cAAc,YAAY,CAAA;AAE1B,YAAY;AACZ,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAC9D,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AAEhF,SAAS;AACT,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAEvE,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AAEzD,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAA;AAG9D,MAAM;AACN,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AAGtD,OAAO;AACP,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAGnC,mBAAmB;AACnB,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAA;AAE5E,mBAAmB;AACnB,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAA"}
@@ -0,0 +1,4 @@
1
+ import { LLMProvider } from '../types.js';
2
+ export type KeyMap = Record<string, string | undefined>;
3
+ export declare function createLLMProvider(model: string, keys: KeyMap): LLMProvider;
4
+ //# sourceMappingURL=providers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"providers.d.ts","sourceRoot":"","sources":["../../src/llm/providers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAc,MAAM,aAAa,CAAA;AAYrD,MAAM,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAA;AAuIvD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,WAAW,CA8B1E"}
@@ -0,0 +1,163 @@
1
+ function requireKey(keys, names, provider) {
2
+ for (const n of names) {
3
+ const v = keys[n];
4
+ if (v)
5
+ return v;
6
+ }
7
+ throw new Error(`No API key for ${provider}. Provide one of: ${names.join(', ')}`);
8
+ }
9
+ // ─── Anthropic (Claude) over fetch ────────────────────────────────────────────
10
+ class AnthropicProvider {
11
+ model;
12
+ apiKey;
13
+ name = 'anthropic';
14
+ constructor(model, apiKey) {
15
+ this.model = model;
16
+ this.apiKey = apiKey;
17
+ }
18
+ headers() {
19
+ return {
20
+ 'content-type': 'application/json',
21
+ 'x-api-key': this.apiKey,
22
+ 'anthropic-version': '2023-06-01',
23
+ 'anthropic-dangerous-direct-browser-access': 'true',
24
+ };
25
+ }
26
+ async call(messages, systemPrompt) {
27
+ const res = await fetch('https://api.anthropic.com/v1/messages', {
28
+ method: 'POST',
29
+ headers: this.headers(),
30
+ body: JSON.stringify({
31
+ model: this.model,
32
+ max_tokens: 2048,
33
+ system: systemPrompt,
34
+ messages: messages.map(m => ({ role: m.role, content: m.content })),
35
+ }),
36
+ });
37
+ if (!res.ok)
38
+ throw new Error(`Anthropic ${res.status}: ${(await res.text()).slice(0, 200)}`);
39
+ const data = (await res.json());
40
+ const block = data.content.find(b => b.type === 'text');
41
+ if (!block?.text)
42
+ throw new Error('Anthropic returned no text block');
43
+ return block.text;
44
+ }
45
+ async callStructured(schema, toolName, prompt) {
46
+ const res = await fetch('https://api.anthropic.com/v1/messages', {
47
+ method: 'POST',
48
+ headers: this.headers(),
49
+ body: JSON.stringify({
50
+ model: this.model,
51
+ max_tokens: 1024,
52
+ tools: [{ name: toolName, description: 'Extract structured data matching the schema.', input_schema: schema }],
53
+ tool_choice: { type: 'tool', name: toolName },
54
+ messages: [{ role: 'user', content: prompt }],
55
+ }),
56
+ });
57
+ if (!res.ok)
58
+ throw new Error(`Anthropic ${res.status}: ${(await res.text()).slice(0, 200)}`);
59
+ const data = (await res.json());
60
+ const tool = data.content.find(b => b.type === 'tool_use');
61
+ if (!tool) {
62
+ const text = data.content.find(b => b.type === 'text')?.text ?? '';
63
+ throw new Error(`Model refused structured output: ${text.slice(0, 200)}`);
64
+ }
65
+ return tool.input;
66
+ }
67
+ }
68
+ // ─── OpenAI-compatible over fetch ─────────────────────────────────────────────
69
+ class OpenAICompatProvider {
70
+ name;
71
+ model;
72
+ apiKey;
73
+ baseURL;
74
+ constructor(name, model, apiKey, baseURL = 'https://api.openai.com/v1') {
75
+ this.name = name;
76
+ this.model = model;
77
+ this.apiKey = apiKey;
78
+ this.baseURL = baseURL;
79
+ }
80
+ headers() {
81
+ return { 'content-type': 'application/json', authorization: `Bearer ${this.apiKey}` };
82
+ }
83
+ async call(messages, systemPrompt) {
84
+ const res = await fetch(`${this.baseURL}/chat/completions`, {
85
+ method: 'POST',
86
+ headers: this.headers(),
87
+ body: JSON.stringify({
88
+ model: this.model,
89
+ max_tokens: 2048,
90
+ messages: [{ role: 'system', content: systemPrompt }, ...messages.map(m => ({ role: m.role, content: m.content }))],
91
+ }),
92
+ });
93
+ if (!res.ok)
94
+ throw new Error(`${this.name} ${res.status}: ${(await res.text()).slice(0, 200)}`);
95
+ const data = (await res.json());
96
+ const content = data.choices[0]?.message?.content;
97
+ if (!content)
98
+ throw new Error(`Empty response from ${this.name}`);
99
+ return content;
100
+ }
101
+ async callStructured(schema, toolName, prompt) {
102
+ const strict = this.model.startsWith('gpt-4o') || /^o[1-9]/.test(this.model);
103
+ const body = {
104
+ model: this.model,
105
+ max_tokens: 1024,
106
+ messages: [{ role: 'user', content: prompt }],
107
+ };
108
+ if (strict) {
109
+ body.response_format = { type: 'json_schema', json_schema: { name: toolName, strict: true, schema } };
110
+ }
111
+ else {
112
+ body.response_format = { type: 'json_object' };
113
+ body.messages[0].content =
114
+ `${prompt}\n\nReturn ONLY JSON matching:\n${JSON.stringify(schema)}`;
115
+ }
116
+ const res = await fetch(`${this.baseURL}/chat/completions`, {
117
+ method: 'POST',
118
+ headers: this.headers(),
119
+ body: JSON.stringify(body),
120
+ });
121
+ if (!res.ok)
122
+ throw new Error(`${this.name} ${res.status}: ${(await res.text()).slice(0, 200)}`);
123
+ const data = (await res.json());
124
+ const choice = data.choices[0];
125
+ if (choice.finish_reason === 'length')
126
+ throw new Error('Response truncated by max_tokens');
127
+ if (choice.message.refusal)
128
+ throw new Error(`Model refused: ${choice.message.refusal}`);
129
+ return JSON.parse(choice.message.content);
130
+ }
131
+ }
132
+ // ─── Factory — model string → provider ────────────────────────────────────────
133
+ export function createLLMProvider(model, keys) {
134
+ const lc = model.toLowerCase();
135
+ if (lc.startsWith('claude-') || lc.startsWith('anthropic/')) {
136
+ const m = lc.startsWith('anthropic/') ? model.slice('anthropic/'.length) : model;
137
+ return new AnthropicProvider(m, requireKey(keys, ['ANTHROPIC_API_KEY'], 'anthropic'));
138
+ }
139
+ if (lc.startsWith('openrouter/')) {
140
+ return new OpenAICompatProvider('openrouter', model.slice('openrouter/'.length), requireKey(keys, ['OPENROUTER_API_KEY'], 'openrouter'), 'https://openrouter.ai/api/v1');
141
+ }
142
+ if (lc.startsWith('groq/')) {
143
+ return new OpenAICompatProvider('groq', model.slice('groq/'.length), requireKey(keys, ['GROQ_API_KEY'], 'groq'), 'https://api.groq.com/openai/v1');
144
+ }
145
+ if (lc.startsWith('gemini/') || lc.startsWith('gemini-')) {
146
+ const m = lc.startsWith('gemini/') ? model.slice('gemini/'.length) : model;
147
+ return new OpenAICompatProvider('gemini', m, requireKey(keys, ['GEMINI_API_KEY', 'GOOGLE_API_KEY'], 'gemini'), 'https://generativelanguage.googleapis.com/v1beta/openai');
148
+ }
149
+ if (lc.startsWith('mistral/') || lc.startsWith('mistral-') || lc.startsWith('open-mistral')) {
150
+ const m = lc.startsWith('mistral/') ? model.slice('mistral/'.length) : model;
151
+ return new OpenAICompatProvider('mistral', m, requireKey(keys, ['MISTRAL_API_KEY'], 'mistral'), 'https://api.mistral.ai/v1');
152
+ }
153
+ if (lc.startsWith('ollama/') || lc.startsWith('ollama:')) {
154
+ const m = model.replace(/^ollama[/:]/i, '');
155
+ const base = keys.OLLAMA_BASE_URL ?? 'http://localhost:11434';
156
+ return new OpenAICompatProvider('ollama', m, 'ollama', `${base}/v1`);
157
+ }
158
+ if (lc.startsWith('gpt-') || /^o[1-9]/.test(lc)) {
159
+ return new OpenAICompatProvider('openai', model, requireKey(keys, ['OPENAI_API_KEY'], 'openai'));
160
+ }
161
+ return new OpenAICompatProvider('openai', model, requireKey(keys, ['OPENAI_API_KEY'], 'openai'));
162
+ }
163
+ //# sourceMappingURL=providers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"providers.js","sourceRoot":"","sources":["../../src/llm/providers.ts"],"names":[],"mappings":"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"}
package/dist/loop.d.ts ADDED
@@ -0,0 +1,16 @@
1
+ import { DemonManifest, DemonState, Watcher, LLMProvider, ActionProvider, Clock, Logger, KVStore } from './types.js';
2
+ export interface LoopConfig {
3
+ manifest: DemonManifest;
4
+ watchers: Watcher[];
5
+ llm: LLMProvider;
6
+ actions: Map<string, ActionProvider>;
7
+ credentials: Map<string, Record<string, string>>;
8
+ logger: Logger;
9
+ clock: Clock;
10
+ storage: KVStore;
11
+ onState?: (updates: Partial<DemonState>) => void;
12
+ startCycle?: number;
13
+ maxCycles?: number;
14
+ }
15
+ export declare function runLoop(config: LoopConfig): Promise<void>;
16
+ //# sourceMappingURL=loop.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loop.d.ts","sourceRoot":"","sources":["../src/loop.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,UAAU,EACV,OAAO,EACP,WAAW,EACX,cAAc,EAMd,KAAK,EACL,MAAM,EACN,OAAO,EACR,MAAM,YAAY,CAAA;AAUnB,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,aAAa,CAAA;IACvB,QAAQ,EAAE,OAAO,EAAE,CAAA;IACnB,GAAG,EAAE,WAAW,CAAA;IAChB,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAA;IACpC,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IAChD,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,KAAK,CAAA;IAEZ,OAAO,EAAE,OAAO,CAAA;IAEhB,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,UAAU,CAAC,KAAK,IAAI,CAAA;IAEhD,UAAU,CAAC,EAAE,MAAM,CAAA;IAEnB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAkHD,wBAAsB,OAAO,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAsD/D"}
package/dist/loop.js ADDED
@@ -0,0 +1,142 @@
1
+ import { createMemoryManager } from './memory/manager.js';
2
+ import { buildDemonPrompt, splitPrompt, parseLLMDecision } from './reasoning.js';
3
+ import { parseInterval } from './util/time.js';
4
+ function generateEntryId(now) {
5
+ return `${now}-${Math.floor(now % 1000).toString(36)}`;
6
+ }
7
+ function formatContext(ctx) {
8
+ return [
9
+ '=== WHAT I KNOW (accumulated over time) ===',
10
+ ctx.narrative || 'Nothing yet — this is early in my run.',
11
+ '',
12
+ '=== RECENT HISTORY ===',
13
+ ctx.recentEpisodes,
14
+ '',
15
+ '=== CURRENT ENTITY STATES ===',
16
+ ctx.relevantFacts,
17
+ ].join('\n');
18
+ }
19
+ async function collectObservations(watchers, logger, now) {
20
+ const results = await Promise.allSettled(watchers.map(w => w.collect()));
21
+ const observations = [];
22
+ for (let i = 0; i < results.length; i++) {
23
+ const r = results[i];
24
+ const w = watchers[i];
25
+ if (r.status === 'fulfilled') {
26
+ observations.push(...r.value);
27
+ logger.debug(`Watcher ${w.type} returned ${r.value.length} observation(s)`);
28
+ }
29
+ else {
30
+ const errMsg = r.reason?.message ?? String(r.reason);
31
+ logger.error(`Watcher ${w.type} failed`, { error: errMsg });
32
+ observations.push({ watcherType: w.type, data: { error: errMsg }, summary: `Watcher ${w.type} failed: ${errMsg}`, timestamp: now });
33
+ }
34
+ }
35
+ return observations;
36
+ }
37
+ async function callLLM(manifest, observations, contextSummary, cycleNum, llm, logger) {
38
+ const payload = observations.map(o => ({ watcherType: String(o.watcherType), summary: o.summary, data: o.data }));
39
+ const combined = buildDemonPrompt(manifest.purpose, contextSummary, payload);
40
+ const { systemPrompt, userContent } = splitPrompt(combined);
41
+ // List actions with provider/action as SEPARATE fields so the model fills the
42
+ // decision schema's action.provider and action.action correctly (not a single
43
+ // concatenated "provider.action" string).
44
+ const actionList = manifest.actions
45
+ .map(a => `- provider: "${a.provider}", action: "${a.action}"`)
46
+ .join('\n');
47
+ const user = `Demon: ${manifest.name}\nCycle: #${cycleNum}\nAction mode: ${manifest.action_mode}\n\nAvailable actions (when you act, set action.provider and action.action to one of these pairs exactly):\n${actionList}\n\n${userContent}`;
48
+ const raw = await llm.call([{ role: 'user', content: user }], systemPrompt);
49
+ logger.debug('Raw LLM response', { raw: raw.slice(0, 300) });
50
+ return parseLLMDecision(raw);
51
+ }
52
+ // Normalize an instruction's provider/action. Models sometimes return the
53
+ // available action verbatim as "provider.action" (e.g. "log.info") in the
54
+ // provider field. If the raw provider isn't registered but splits into a
55
+ // known provider + action, recover it rather than failing the dispatch.
56
+ function normalizeInstruction(instruction, actions) {
57
+ if (actions.has(instruction.provider))
58
+ return instruction;
59
+ const dot = instruction.provider.indexOf('.');
60
+ if (dot > 0) {
61
+ const provider = instruction.provider.slice(0, dot);
62
+ const action = instruction.provider.slice(dot + 1);
63
+ if (actions.has(provider)) {
64
+ return { provider, action: instruction.action || action, params: instruction.params };
65
+ }
66
+ }
67
+ return instruction;
68
+ }
69
+ async function executeInstruction(rawInstruction, actions, credentials, dryRun, logger, now) {
70
+ const instruction = normalizeInstruction(rawInstruction, actions);
71
+ // Dry-run short-circuits BEFORE requiring a registered provider — it only
72
+ // reports what *would* happen, so a missing provider must not error here.
73
+ if (dryRun) {
74
+ logger.info(`[DRY RUN] Would execute: ${instruction.provider}.${instruction.action}`, { params: instruction.params });
75
+ return { provider: instruction.provider, action: instruction.action, params: instruction.params, result: { dryRun: true }, dryRun: true, timestamp: now };
76
+ }
77
+ const provider = actions.get(instruction.provider);
78
+ if (!provider) {
79
+ const err = `No action provider registered for "${instruction.provider}". Available: ${[...actions.keys()].join(', ') || '(none)'}`;
80
+ logger.error(err);
81
+ return { provider: instruction.provider, action: instruction.action, params: instruction.params, error: err, dryRun, timestamp: now };
82
+ }
83
+ try {
84
+ const result = await provider.execute(instruction, credentials.get(instruction.provider) ?? {});
85
+ logger.info(`Action executed: ${instruction.provider}.${instruction.action}`, { result });
86
+ return { provider: instruction.provider, action: instruction.action, params: instruction.params, result, dryRun: false, timestamp: now };
87
+ }
88
+ catch (err) {
89
+ const errMsg = err.message;
90
+ logger.error(`Action failed: ${instruction.provider}.${instruction.action}`, { error: errMsg });
91
+ return { provider: instruction.provider, action: instruction.action, params: instruction.params, error: errMsg, dryRun: false, timestamp: now };
92
+ }
93
+ }
94
+ export async function runLoop(config) {
95
+ const { manifest, watchers, llm, actions, credentials, logger, clock, storage, onState } = config;
96
+ const intervalMs = parseInterval(manifest.interval);
97
+ const memory = await createMemoryManager(storage, manifest, llm);
98
+ let cycleNum = config.startCycle ?? 0;
99
+ logger.info('Observation loop started', { interval: manifest.interval, watcherCount: watchers.length, actionCount: manifest.actions.length, model: llm.model });
100
+ while (config.maxCycles === undefined || cycleNum < config.maxCycles) {
101
+ const cycleStart = clock.now();
102
+ cycleNum += 1;
103
+ const nowIso = new Date(cycleStart).toISOString();
104
+ logger.info(`Cycle #${cycleNum} starting`);
105
+ onState?.({ lastCheck: nowIso, status: 'running' });
106
+ const observations = await collectObservations(watchers, logger, nowIso);
107
+ logger.info(`Collected ${observations.length} observation(s)`, { cycleNum });
108
+ const contextSummary = formatContext(await memory.buildContext(observations));
109
+ let decision;
110
+ try {
111
+ decision = await callLLM(manifest, observations, contextSummary, cycleNum, llm, logger);
112
+ logger.info(`Decision: ${decision.decision}`, { reasoning: decision.reasoning });
113
+ }
114
+ catch (err) {
115
+ const errMsg = err.message;
116
+ logger.error('LLM call failed', { error: errMsg });
117
+ decision = { decision: 'wait', reasoning: `LLM error: ${errMsg}` };
118
+ }
119
+ let actionFired;
120
+ if (decision.decision === 'act' && decision.action) {
121
+ const dryRun = manifest.action_mode === 'dry_run';
122
+ actionFired = await executeInstruction(decision.action, actions, credentials, dryRun, logger, nowIso);
123
+ if (!actionFired.error && !actionFired.dryRun)
124
+ onState?.({ actionsCount: undefined });
125
+ }
126
+ else {
127
+ logger.debug(`Waiting: ${decision.reasoning}`);
128
+ }
129
+ const entry = { id: generateEntryId(cycleStart), timestamp: nowIso, cycleNumber: cycleNum, observations, decision, actionFired };
130
+ await memory.recordCycle(entry);
131
+ onState?.({ cycles: cycleNum, lastCheck: nowIso, status: 'running' });
132
+ const elapsed = clock.now() - cycleStart;
133
+ logger.info(`Cycle #${cycleNum} complete`, { durationMs: elapsed, decision: decision.decision, observations: observations.length });
134
+ if (config.maxCycles !== undefined && cycleNum >= config.maxCycles)
135
+ break;
136
+ const sleepMs = Math.max(0, intervalMs - elapsed);
137
+ if (sleepMs > 0)
138
+ await clock.sleep(sleepMs);
139
+ }
140
+ memory.close();
141
+ }
142
+ //# sourceMappingURL=loop.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loop.js","sourceRoot":"","sources":["../src/loop.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import { MemoryEntry, KVStore } from '../types.js';
2
+ export interface EpisodeStore {
3
+ append(entry: MemoryEntry): Promise<void>;
4
+ getRecent(n?: number): Promise<MemoryEntry[]>;
5
+ buildContextSummary(n?: number): Promise<string>;
6
+ getDemonAge(): Promise<{
7
+ cycles: number;
8
+ startedAt: Date | null;
9
+ }>;
10
+ }
11
+ export declare function createEpisodeStore(kv: KVStore, key?: string): EpisodeStore;
12
+ //# sourceMappingURL=episodes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"episodes.d.ts","sourceRoot":"","sources":["../../src/memory/episodes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAOlD,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACzC,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAAA;IAC7C,mBAAmB,CAAC,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IAChD,WAAW,IAAI,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,IAAI,GAAG,IAAI,CAAA;KAAE,CAAC,CAAA;CACnE;AAED,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,OAAO,EAAE,GAAG,SAAoB,GAAG,YAAY,CAoDrF"}
@@ -0,0 +1,50 @@
1
+ export function createEpisodeStore(kv, key = 'decisions.jsonl') {
2
+ function parseLines(lines) {
3
+ return lines.reduce((acc, line) => {
4
+ try {
5
+ acc.push(JSON.parse(line));
6
+ }
7
+ catch {
8
+ // skip corrupt
9
+ }
10
+ return acc;
11
+ }, []);
12
+ }
13
+ async function append(entry) {
14
+ await kv.append(key, JSON.stringify(entry));
15
+ }
16
+ async function getRecent(n = 10) {
17
+ return parseLines(await kv.readLines(key, n));
18
+ }
19
+ async function buildContextSummary(n = 10) {
20
+ const entries = await getRecent(n);
21
+ if (entries.length === 0) {
22
+ return 'No prior decisions recorded. This is the first cycle.';
23
+ }
24
+ const lines = entries.map(e => {
25
+ const decision = e.decision.decision.toUpperCase();
26
+ const reasoning = e.decision.reasoning.slice(0, 200);
27
+ const obsCount = e.observations.length;
28
+ const actionInfo = e.actionFired
29
+ ? ` | Action: ${e.actionFired.provider}.${e.actionFired.action}${e.actionFired.dryRun ? ' (dry-run)' : ''}${e.actionFired.error ? ` [FAILED: ${e.actionFired.error.slice(0, 80)}]` : ''}`
30
+ : '';
31
+ return ` Cycle #${e.cycleNumber} [${e.timestamp}] → ${decision}: ${reasoning}${actionInfo} (${obsCount} observation${obsCount !== 1 ? 's' : ''})`;
32
+ });
33
+ return `Recent decision history (last ${entries.length} cycle${entries.length !== 1 ? 's' : ''}):\n${lines.join('\n')}`;
34
+ }
35
+ async function getDemonAge() {
36
+ const lines = await kv.readLines(key);
37
+ if (lines.length === 0)
38
+ return { cycles: 0, startedAt: null };
39
+ let startedAt = null;
40
+ try {
41
+ startedAt = new Date(JSON.parse(lines[0]).timestamp);
42
+ }
43
+ catch {
44
+ // corrupt first entry
45
+ }
46
+ return { cycles: lines.length, startedAt };
47
+ }
48
+ return { append, getRecent, buildContextSummary, getDemonAge };
49
+ }
50
+ //# sourceMappingURL=episodes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"episodes.js","sourceRoot":"","sources":["../../src/memory/episodes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { FactsStore, KVStore } from '../types.js';
2
+ export declare function createFactsStore(kv: KVStore, key?: string): Promise<FactsStore>;
3
+ //# sourceMappingURL=facts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"facts.d.ts","sourceRoot":"","sources":["../../src/memory/facts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,UAAU,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAqBvD,wBAAsB,gBAAgB,CACpC,EAAE,EAAE,OAAO,EACX,GAAG,SAAe,GACjB,OAAO,CAAC,UAAU,CAAC,CA6FrB"}