@duetso/agent 0.1.20

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 (148) hide show
  1. package/LICENSE +189 -0
  2. package/README.md +315 -0
  3. package/dist/package.json +84 -0
  4. package/dist/src/cli.d.ts +23 -0
  5. package/dist/src/cli.d.ts.map +1 -0
  6. package/dist/src/cli.js +754 -0
  7. package/dist/src/cli.js.map +1 -0
  8. package/dist/src/core/serializer.d.ts +3 -0
  9. package/dist/src/core/serializer.d.ts.map +1 -0
  10. package/dist/src/core/serializer.js +22 -0
  11. package/dist/src/core/serializer.js.map +1 -0
  12. package/dist/src/core/structured-output.d.ts +13 -0
  13. package/dist/src/core/structured-output.d.ts.map +1 -0
  14. package/dist/src/core/structured-output.js +41 -0
  15. package/dist/src/core/structured-output.js.map +1 -0
  16. package/dist/src/guardrails/firewall.d.ts +7 -0
  17. package/dist/src/guardrails/firewall.d.ts.map +1 -0
  18. package/dist/src/guardrails/firewall.js +31 -0
  19. package/dist/src/guardrails/firewall.js.map +1 -0
  20. package/dist/src/guardrails/pattern.d.ts +13 -0
  21. package/dist/src/guardrails/pattern.d.ts.map +1 -0
  22. package/dist/src/guardrails/pattern.js +70 -0
  23. package/dist/src/guardrails/pattern.js.map +1 -0
  24. package/dist/src/guardrails/semantic.d.ts +14 -0
  25. package/dist/src/guardrails/semantic.d.ts.map +1 -0
  26. package/dist/src/guardrails/semantic.js +47 -0
  27. package/dist/src/guardrails/semantic.js.map +1 -0
  28. package/dist/src/index.d.ts +20 -0
  29. package/dist/src/index.d.ts.map +1 -0
  30. package/dist/src/index.js +20 -0
  31. package/dist/src/index.js.map +1 -0
  32. package/dist/src/lib/compact-json.d.ts +11 -0
  33. package/dist/src/lib/compact-json.d.ts.map +1 -0
  34. package/dist/src/lib/compact-json.js +36 -0
  35. package/dist/src/lib/compact-json.js.map +1 -0
  36. package/dist/src/lib/xml.d.ts +3 -0
  37. package/dist/src/lib/xml.d.ts.map +1 -0
  38. package/dist/src/lib/xml.js +9 -0
  39. package/dist/src/lib/xml.js.map +1 -0
  40. package/dist/src/memory/observation-groups.d.ts +15 -0
  41. package/dist/src/memory/observation-groups.d.ts.map +1 -0
  42. package/dist/src/memory/observation-groups.js +159 -0
  43. package/dist/src/memory/observation-groups.js.map +1 -0
  44. package/dist/src/memory/observational-prompts.d.ts +27 -0
  45. package/dist/src/memory/observational-prompts.d.ts.map +1 -0
  46. package/dist/src/memory/observational-prompts.js +237 -0
  47. package/dist/src/memory/observational-prompts.js.map +1 -0
  48. package/dist/src/memory/observational.d.ts +63 -0
  49. package/dist/src/memory/observational.d.ts.map +1 -0
  50. package/dist/src/memory/observational.js +605 -0
  51. package/dist/src/memory/observational.js.map +1 -0
  52. package/dist/src/memory/storage.d.ts +3 -0
  53. package/dist/src/memory/storage.d.ts.map +1 -0
  54. package/dist/src/memory/storage.js +127 -0
  55. package/dist/src/memory/storage.js.map +1 -0
  56. package/dist/src/memory/store.d.ts +13 -0
  57. package/dist/src/memory/store.d.ts.map +1 -0
  58. package/dist/src/memory/store.js +106 -0
  59. package/dist/src/memory/store.js.map +1 -0
  60. package/dist/src/model-resolution/duet-gateway.d.ts +35 -0
  61. package/dist/src/model-resolution/duet-gateway.d.ts.map +1 -0
  62. package/dist/src/model-resolution/duet-gateway.js +56 -0
  63. package/dist/src/model-resolution/duet-gateway.js.map +1 -0
  64. package/dist/src/model-resolution/index.d.ts +31 -0
  65. package/dist/src/model-resolution/index.d.ts.map +1 -0
  66. package/dist/src/model-resolution/index.js +129 -0
  67. package/dist/src/model-resolution/index.js.map +1 -0
  68. package/dist/src/session/session-manager.d.ts +45 -0
  69. package/dist/src/session/session-manager.d.ts.map +1 -0
  70. package/dist/src/session/session-manager.js +94 -0
  71. package/dist/src/session/session-manager.js.map +1 -0
  72. package/dist/src/session/session.d.ts +113 -0
  73. package/dist/src/session/session.d.ts.map +1 -0
  74. package/dist/src/session/session.js +308 -0
  75. package/dist/src/session/session.js.map +1 -0
  76. package/dist/src/tui/app.d.ts +60 -0
  77. package/dist/src/tui/app.d.ts.map +1 -0
  78. package/dist/src/tui/app.js +742 -0
  79. package/dist/src/tui/app.js.map +1 -0
  80. package/dist/src/turn-runner/agent-events.d.ts +5 -0
  81. package/dist/src/turn-runner/agent-events.d.ts.map +1 -0
  82. package/dist/src/turn-runner/agent-events.js +59 -0
  83. package/dist/src/turn-runner/agent-events.js.map +1 -0
  84. package/dist/src/turn-runner/prompts.d.ts +13 -0
  85. package/dist/src/turn-runner/prompts.d.ts.map +1 -0
  86. package/dist/src/turn-runner/prompts.js +79 -0
  87. package/dist/src/turn-runner/prompts.js.map +1 -0
  88. package/dist/src/turn-runner/shell-state-handle.d.ts +32 -0
  89. package/dist/src/turn-runner/shell-state-handle.d.ts.map +1 -0
  90. package/dist/src/turn-runner/shell-state-handle.js +168 -0
  91. package/dist/src/turn-runner/shell-state-handle.js.map +1 -0
  92. package/dist/src/turn-runner/skill-context.d.ts +26 -0
  93. package/dist/src/turn-runner/skill-context.d.ts.map +1 -0
  94. package/dist/src/turn-runner/skill-context.js +110 -0
  95. package/dist/src/turn-runner/skill-context.js.map +1 -0
  96. package/dist/src/turn-runner/skills.d.ts +35 -0
  97. package/dist/src/turn-runner/skills.d.ts.map +1 -0
  98. package/dist/src/turn-runner/skills.js +130 -0
  99. package/dist/src/turn-runner/skills.js.map +1 -0
  100. package/dist/src/turn-runner/state-machine-controller.d.ts +90 -0
  101. package/dist/src/turn-runner/state-machine-controller.d.ts.map +1 -0
  102. package/dist/src/turn-runner/state-machine-controller.js +289 -0
  103. package/dist/src/turn-runner/state-machine-controller.js.map +1 -0
  104. package/dist/src/turn-runner/state-machine-session.d.ts +27 -0
  105. package/dist/src/turn-runner/state-machine-session.d.ts.map +1 -0
  106. package/dist/src/turn-runner/state-machine-session.js +189 -0
  107. package/dist/src/turn-runner/state-machine-session.js.map +1 -0
  108. package/dist/src/turn-runner/tools.d.ts +193 -0
  109. package/dist/src/turn-runner/tools.d.ts.map +1 -0
  110. package/dist/src/turn-runner/tools.js +509 -0
  111. package/dist/src/turn-runner/tools.js.map +1 -0
  112. package/dist/src/turn-runner/turn-runner.d.ts +160 -0
  113. package/dist/src/turn-runner/turn-runner.d.ts.map +1 -0
  114. package/dist/src/turn-runner/turn-runner.js +907 -0
  115. package/dist/src/turn-runner/turn-runner.js.map +1 -0
  116. package/dist/src/turn-runner/turn-state.d.ts +6 -0
  117. package/dist/src/turn-runner/turn-state.d.ts.map +1 -0
  118. package/dist/src/turn-runner/turn-state.js +32 -0
  119. package/dist/src/turn-runner/turn-state.js.map +1 -0
  120. package/dist/src/turn-runner/usage-accounting.d.ts +7 -0
  121. package/dist/src/turn-runner/usage-accounting.d.ts.map +1 -0
  122. package/dist/src/turn-runner/usage-accounting.js +49 -0
  123. package/dist/src/turn-runner/usage-accounting.js.map +1 -0
  124. package/dist/src/types/agent.d.ts +15 -0
  125. package/dist/src/types/agent.d.ts.map +1 -0
  126. package/dist/src/types/agent.js +2 -0
  127. package/dist/src/types/agent.js.map +1 -0
  128. package/dist/src/types/config.d.ts +37 -0
  129. package/dist/src/types/config.d.ts.map +1 -0
  130. package/dist/src/types/config.js +2 -0
  131. package/dist/src/types/config.js.map +1 -0
  132. package/dist/src/types/guardrails.d.ts +34 -0
  133. package/dist/src/types/guardrails.d.ts.map +1 -0
  134. package/dist/src/types/guardrails.js +2 -0
  135. package/dist/src/types/guardrails.js.map +1 -0
  136. package/dist/src/types/memory.d.ts +151 -0
  137. package/dist/src/types/memory.d.ts.map +1 -0
  138. package/dist/src/types/memory.js +2 -0
  139. package/dist/src/types/memory.js.map +1 -0
  140. package/dist/src/types/protocol.d.ts +426 -0
  141. package/dist/src/types/protocol.d.ts.map +1 -0
  142. package/dist/src/types/protocol.js +2 -0
  143. package/dist/src/types/protocol.js.map +1 -0
  144. package/dist/src/types/state-machine.d.ts +344 -0
  145. package/dist/src/types/state-machine.d.ts.map +1 -0
  146. package/dist/src/types/state-machine.js +2 -0
  147. package/dist/src/types/state-machine.js.map +1 -0
  148. package/package.json +84 -0
@@ -0,0 +1,127 @@
1
+ import { PGlite } from "@electric-sql/pglite";
2
+ import { mkdirSync } from "node:fs";
3
+ import { dirname, join } from "node:path";
4
+ export async function loadStoredMemory(memoryPath, cwd, store) {
5
+ if (!memoryPath) {
6
+ return async () => { };
7
+ }
8
+ const database = await openMemoryDatabase(resolveMemoryPath(memoryPath, cwd));
9
+ const snapshot = await readMemorySnapshot(database);
10
+ await store.replaceObservations(snapshot.observations);
11
+ let writeQueue = Promise.resolve();
12
+ const enqueueWrite = (event) => {
13
+ writeQueue = writeQueue.then(() => persistMemoryEvent(database, event));
14
+ void writeQueue;
15
+ };
16
+ const unsubscribe = store.on(enqueueWrite);
17
+ return async () => {
18
+ unsubscribe();
19
+ await writeQueue;
20
+ await database.close();
21
+ };
22
+ }
23
+ async function openMemoryDatabase(path) {
24
+ mkdirSync(dirname(path), { recursive: true });
25
+ const database = new PGlite(path);
26
+ await database.exec(`
27
+ CREATE TABLE IF NOT EXISTS observations (
28
+ id TEXT PRIMARY KEY,
29
+ created_at BIGINT NOT NULL,
30
+ observed_date TEXT NOT NULL,
31
+ referenced_date TEXT,
32
+ relative_date TEXT,
33
+ time_of_day TEXT,
34
+ priority TEXT NOT NULL,
35
+ scope TEXT NOT NULL,
36
+ source_json TEXT NOT NULL,
37
+ content TEXT NOT NULL,
38
+ tags_json TEXT NOT NULL
39
+ );
40
+ `);
41
+ return database;
42
+ }
43
+ async function readMemorySnapshot(database) {
44
+ const result = await database.query(`SELECT id, created_at, observed_date, referenced_date, relative_date, time_of_day, priority, scope, source_json, content, tags_json
45
+ FROM observations
46
+ ORDER BY created_at ASC`);
47
+ const observations = result.rows.map(rowToObservation);
48
+ return {
49
+ observations,
50
+ estimatedTokens: {
51
+ observations: estimateTokens(observations.map((item) => item.content).join("\n")),
52
+ },
53
+ updatedAt: Date.now(),
54
+ };
55
+ }
56
+ async function persistMemoryEvent(database, event) {
57
+ if (event.type === "observation_appended") {
58
+ await upsertObservation(database, event.observation);
59
+ return;
60
+ }
61
+ await syncObservations(database, event.observations);
62
+ }
63
+ async function syncObservations(database, observations) {
64
+ const ids = observations.map((observation) => observation.id);
65
+ await database.transaction(async (tx) => {
66
+ if (ids.length === 0) {
67
+ await tx.exec("DELETE FROM observations");
68
+ }
69
+ else {
70
+ await tx.query("DELETE FROM observations WHERE NOT (id = ANY($1::text[]))", [ids]);
71
+ }
72
+ for (const observation of observations) {
73
+ await upsertObservation(tx, observation);
74
+ }
75
+ });
76
+ }
77
+ async function upsertObservation(database, observation) {
78
+ await database.query(`INSERT INTO observations (
79
+ id, created_at, observed_date, referenced_date, relative_date, time_of_day,
80
+ priority, scope, source_json, content, tags_json
81
+ ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
82
+ ON CONFLICT (id) DO UPDATE SET
83
+ created_at = EXCLUDED.created_at,
84
+ observed_date = EXCLUDED.observed_date,
85
+ referenced_date = EXCLUDED.referenced_date,
86
+ relative_date = EXCLUDED.relative_date,
87
+ time_of_day = EXCLUDED.time_of_day,
88
+ priority = EXCLUDED.priority,
89
+ scope = EXCLUDED.scope,
90
+ source_json = EXCLUDED.source_json,
91
+ content = EXCLUDED.content,
92
+ tags_json = EXCLUDED.tags_json`, [
93
+ observation.id,
94
+ observation.createdAt,
95
+ observation.observedDate,
96
+ observation.referencedDate ?? null,
97
+ observation.relativeDate ?? null,
98
+ observation.timeOfDay ?? null,
99
+ observation.priority,
100
+ observation.scope,
101
+ JSON.stringify(observation.source),
102
+ observation.content,
103
+ JSON.stringify(observation.tags),
104
+ ]);
105
+ }
106
+ function resolveMemoryPath(path, cwd) {
107
+ return path.startsWith("/") ? path : join(cwd, path);
108
+ }
109
+ function estimateTokens(text) {
110
+ return Math.ceil(text.length / 4);
111
+ }
112
+ function rowToObservation(row) {
113
+ return {
114
+ id: row.id,
115
+ createdAt: row.created_at,
116
+ observedDate: row.observed_date,
117
+ referencedDate: row.referenced_date ?? undefined,
118
+ relativeDate: row.relative_date ?? undefined,
119
+ timeOfDay: row.time_of_day ?? undefined,
120
+ priority: row.priority,
121
+ scope: row.scope,
122
+ source: JSON.parse(row.source_json),
123
+ content: row.content,
124
+ tags: JSON.parse(row.tags_json),
125
+ };
126
+ }
127
+ //# sourceMappingURL=storage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.js","sourceRoot":"","sources":["../../../src/memory/storage.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { MemoryStoreEventHandler, Observation, ObservationQuery, ObservationalMemorySnapshot } from "../types/memory.js";
2
+ export declare class MemoryStore {
3
+ private observations;
4
+ private handlers;
5
+ on(handler: MemoryStoreEventHandler): () => void;
6
+ appendObservation(input: Omit<Observation, "id" | "createdAt">): Promise<Observation>;
7
+ recall(query: ObservationQuery): Promise<Observation[]>;
8
+ getSnapshot(): Promise<ObservationalMemorySnapshot>;
9
+ replaceObservations(observations: Observation[]): Promise<void>;
10
+ render(snapshot: ObservationalMemorySnapshot): string;
11
+ private emit;
12
+ }
13
+ //# sourceMappingURL=store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../../src/memory/store.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEV,uBAAuB,EACvB,WAAW,EAEX,gBAAgB,EAChB,2BAA2B,EAC5B,MAAM,oBAAoB,CAAC;AAE5B,qBAAa,WAAW;IACtB,OAAO,CAAC,YAAY,CAAuC;IAC3D,OAAO,CAAC,QAAQ,CAAsC;IAEtD,EAAE,CAAC,OAAO,EAAE,uBAAuB,GAAG,MAAM,IAAI;IAO1C,iBAAiB,CAAC,KAAK,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,GAAG,WAAW,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC;IAWrF,MAAM,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IA0BvD,WAAW,IAAI,OAAO,CAAC,2BAA2B,CAAC;IAcnD,mBAAmB,CAAC,YAAY,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAQrE,MAAM,CAAC,QAAQ,EAAE,2BAA2B,GAAG,MAAM;IAQrD,OAAO,CAAC,IAAI;CAKb"}
@@ -0,0 +1,106 @@
1
+ import { nanoid } from "nanoid";
2
+ export class MemoryStore {
3
+ observations = new Map();
4
+ handlers = new Set();
5
+ on(handler) {
6
+ this.handlers.add(handler);
7
+ return () => {
8
+ this.handlers.delete(handler);
9
+ };
10
+ }
11
+ async appendObservation(input) {
12
+ const observation = {
13
+ ...input,
14
+ id: createMemoryId(),
15
+ createdAt: Date.now(),
16
+ };
17
+ this.observations.set(observation.id, observation);
18
+ this.emit({ type: "observation_appended", observation });
19
+ return observation;
20
+ }
21
+ async recall(query) {
22
+ let candidates = Array.from(this.observations.values());
23
+ if (query.scope) {
24
+ candidates = candidates.filter((observation) => observation.scope === query.scope);
25
+ }
26
+ if (query.tags?.length) {
27
+ candidates = candidates.filter((observation) => query.tags.some((tag) => observation.tags.includes(tag)));
28
+ }
29
+ if (query.minPriority) {
30
+ const minRank = priorityRank(query.minPriority);
31
+ candidates = candidates.filter((observation) => priorityRank(observation.priority) >= minRank);
32
+ }
33
+ if (query.query) {
34
+ const terms = tokenize(query.query);
35
+ candidates = candidates.sort((a, b) => textScore(b, terms) - textScore(a, terms));
36
+ }
37
+ else {
38
+ candidates.sort((a, b) => b.createdAt - a.createdAt);
39
+ }
40
+ return candidates.slice(0, query.limit ?? 10);
41
+ }
42
+ async getSnapshot() {
43
+ const observations = Array.from(this.observations.values()).sort((a, b) => a.createdAt - b.createdAt);
44
+ const updatedAt = Date.now();
45
+ return {
46
+ observations,
47
+ estimatedTokens: {
48
+ observations: estimateTokens(observations.map((item) => item.content).join("\n")),
49
+ },
50
+ updatedAt,
51
+ };
52
+ }
53
+ async replaceObservations(observations) {
54
+ this.observations.clear();
55
+ for (const observation of observations) {
56
+ this.observations.set(observation.id, observation);
57
+ }
58
+ this.emit({ type: "observations_replaced", observations });
59
+ }
60
+ render(snapshot) {
61
+ const observationLines = snapshot.observations.map(formatObservation);
62
+ return [
63
+ "## Observations",
64
+ observationLines.length > 0 ? observationLines.join("\n") : "(none)",
65
+ ].join("\n");
66
+ }
67
+ emit(event) {
68
+ for (const handler of this.handlers) {
69
+ handler(event);
70
+ }
71
+ }
72
+ }
73
+ function createMemoryId() {
74
+ return `mem_${nanoid(12)}`;
75
+ }
76
+ function priorityRank(priority) {
77
+ return priority === "high" ? 3 : priority === "medium" ? 2 : 1;
78
+ }
79
+ function priorityMarker(priority) {
80
+ return priority === "high" ? "HIGH" : priority === "medium" ? "MED" : "LOW";
81
+ }
82
+ function formatObservation(observation) {
83
+ const time = observation.timeOfDay ? ` ${observation.timeOfDay}` : "";
84
+ const referenced = observation.referencedDate ? ` [ref: ${observation.referencedDate}]` : "";
85
+ return `- ${priorityMarker(observation.priority)} ${observation.observedDate}${time}${referenced} ${observation.content}`;
86
+ }
87
+ function tokenize(text) {
88
+ return new Set(text
89
+ .toLowerCase()
90
+ .split(/[^a-z0-9]+/)
91
+ .filter(Boolean));
92
+ }
93
+ function textScore(observation, terms) {
94
+ const text = `${observation.content} ${observation.tags.join(" ")}`.toLowerCase();
95
+ let score = priorityRank(observation.priority);
96
+ for (const term of terms) {
97
+ if (text.includes(term)) {
98
+ score += 1;
99
+ }
100
+ }
101
+ return score;
102
+ }
103
+ function estimateTokens(text) {
104
+ return Math.ceil(text.length / 4);
105
+ }
106
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../../src/memory/store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ import { type Model } from "@earendil-works/pi-ai";
2
+ /**
3
+ * The Duet gateway proxies Vercel's AI Gateway 1:1 — same path layout, same
4
+ * request/response contract — and authenticates with a `DUET_API_KEY` token
5
+ * scoped to a single org. Rather than ship a parallel model registry, the
6
+ * `duet-gateway` provider piggybacks on the underlying `vercel-ai-gateway`
7
+ * model definitions and only swaps `baseUrl` to point at Duet (or a custom
8
+ * URL via `DUET_GATEWAY_BASE_URL`).
9
+ *
10
+ * Auth flows through pi-ai's existing vercel-ai-gateway path, which reads
11
+ * `AI_GATEWAY_API_KEY` — the CLI shims that env var from `DUET_API_KEY` at
12
+ * startup so users only need to set the duet token.
13
+ */
14
+ export declare const DUET_GATEWAY_PROVIDER = "duet-gateway";
15
+ export declare const DUET_GATEWAY_API_KEY_ENV = "DUET_API_KEY";
16
+ export declare const DUET_GATEWAY_BASE_URL_ENV = "DUET_GATEWAY_BASE_URL";
17
+ export declare function isDuetGatewayModelName(modelName: string): boolean;
18
+ export declare function getDuetGatewayBaseUrl(): string;
19
+ /**
20
+ * Resolve a `duet-gateway:<modelId>` string to a Model.
21
+ *
22
+ * Looks up the matching vercel-ai-gateway model and clones it with a Duet
23
+ * gateway baseUrl. Returns undefined when the underlying gateway model
24
+ * doesn't exist, mirroring `getModel`'s contract.
25
+ */
26
+ export declare function resolveDuetGatewayModel(modelId: string): Model<any> | undefined;
27
+ /**
28
+ * If `DUET_API_KEY` is set but `AI_GATEWAY_API_KEY` is not, copy it across so
29
+ * the underlying vercel-ai-gateway provider auth path resolves. Idempotent.
30
+ *
31
+ * Called early in CLI startup. No-op when either var is missing or
32
+ * `AI_GATEWAY_API_KEY` is already set (caller wins).
33
+ */
34
+ export declare function shimDuetApiKeyToAiGateway(): void;
35
+ //# sourceMappingURL=duet-gateway.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"duet-gateway.d.ts","sourceRoot":"","sources":["../../../src/model-resolution/duet-gateway.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAK7D;;;;;;;;;;;GAWG;AAEH,eAAO,MAAM,qBAAqB,iBAAkB,CAAC;AACrD,eAAO,MAAM,wBAAwB,iBAAiB,CAAC;AACvD,eAAO,MAAM,yBAAyB,0BAA0B,CAAC;AAEjE,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAEjE;AAED,wBAAgB,qBAAqB,IAAI,MAAM,CAE9C;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,SAAS,CAQ/E;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,IAAI,IAAI,CAKhD"}
@@ -0,0 +1,56 @@
1
+ import { getModel } from "@earendil-works/pi-ai";
2
+ const PROVIDER_PREFIX = "duet-gateway";
3
+ const DEFAULT_BASE_URL = "https://duet.so/api/v1/ai-gateway";
4
+ /**
5
+ * The Duet gateway proxies Vercel's AI Gateway 1:1 — same path layout, same
6
+ * request/response contract — and authenticates with a `DUET_API_KEY` token
7
+ * scoped to a single org. Rather than ship a parallel model registry, the
8
+ * `duet-gateway` provider piggybacks on the underlying `vercel-ai-gateway`
9
+ * model definitions and only swaps `baseUrl` to point at Duet (or a custom
10
+ * URL via `DUET_GATEWAY_BASE_URL`).
11
+ *
12
+ * Auth flows through pi-ai's existing vercel-ai-gateway path, which reads
13
+ * `AI_GATEWAY_API_KEY` — the CLI shims that env var from `DUET_API_KEY` at
14
+ * startup so users only need to set the duet token.
15
+ */
16
+ export const DUET_GATEWAY_PROVIDER = PROVIDER_PREFIX;
17
+ export const DUET_GATEWAY_API_KEY_ENV = "DUET_API_KEY";
18
+ export const DUET_GATEWAY_BASE_URL_ENV = "DUET_GATEWAY_BASE_URL";
19
+ export function isDuetGatewayModelName(modelName) {
20
+ return modelName.startsWith(`${PROVIDER_PREFIX}:`);
21
+ }
22
+ export function getDuetGatewayBaseUrl() {
23
+ return process.env[DUET_GATEWAY_BASE_URL_ENV] ?? DEFAULT_BASE_URL;
24
+ }
25
+ /**
26
+ * Resolve a `duet-gateway:<modelId>` string to a Model.
27
+ *
28
+ * Looks up the matching vercel-ai-gateway model and clones it with a Duet
29
+ * gateway baseUrl. Returns undefined when the underlying gateway model
30
+ * doesn't exist, mirroring `getModel`'s contract.
31
+ */
32
+ export function resolveDuetGatewayModel(modelId) {
33
+ const upstream = getModel("vercel-ai-gateway", modelId);
34
+ if (!upstream)
35
+ return undefined;
36
+ return {
37
+ ...upstream,
38
+ baseUrl: getDuetGatewayBaseUrl(),
39
+ };
40
+ }
41
+ /**
42
+ * If `DUET_API_KEY` is set but `AI_GATEWAY_API_KEY` is not, copy it across so
43
+ * the underlying vercel-ai-gateway provider auth path resolves. Idempotent.
44
+ *
45
+ * Called early in CLI startup. No-op when either var is missing or
46
+ * `AI_GATEWAY_API_KEY` is already set (caller wins).
47
+ */
48
+ export function shimDuetApiKeyToAiGateway() {
49
+ if (process.env.AI_GATEWAY_API_KEY)
50
+ return;
51
+ const duetKey = process.env[DUET_GATEWAY_API_KEY_ENV];
52
+ if (!duetKey)
53
+ return;
54
+ process.env.AI_GATEWAY_API_KEY = duetKey;
55
+ }
56
+ //# sourceMappingURL=duet-gateway.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"duet-gateway.js","sourceRoot":"","sources":["../../../src/model-resolution/duet-gateway.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAc,MAAM,uBAAuB,CAAC;AAE7D,MAAM,eAAe,GAAG,cAAc,CAAC;AACvC,MAAM,gBAAgB,GAAG,mCAAmC,CAAC;AAE7D;;;;;;;;;;;GAWG;AAEH,MAAM,CAAC,MAAM,qBAAqB,GAAG,eAAe,CAAC;AACrD,MAAM,CAAC,MAAM,wBAAwB,GAAG,cAAc,CAAC;AACvD,MAAM,CAAC,MAAM,yBAAyB,GAAG,uBAAuB,CAAC;AAEjE,MAAM,UAAU,sBAAsB,CAAC,SAAiB;IACtD,OAAO,SAAS,CAAC,UAAU,CAAC,GAAG,eAAe,GAAG,CAAC,CAAC;AACrD,CAAC;AAED,MAAM,UAAU,qBAAqB;IACnC,OAAO,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,IAAI,gBAAgB,CAAC;AACpE,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,uBAAuB,CAAC,OAAe;IACrD,MAAM,QAAQ,GAAG,QAAQ,CAAC,mBAA0B,EAAE,OAAc,CAA2B,CAAC;IAChG,IAAI,CAAC,QAAQ;QAAE,OAAO,SAAS,CAAC;IAEhC,OAAO;QACL,GAAG,QAAQ;QACX,OAAO,EAAE,qBAAqB,EAAE;KACjC,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,yBAAyB;IACvC,IAAI,OAAO,CAAC,GAAG,CAAC,kBAAkB;QAAE,OAAO;IAC3C,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC;IACtD,IAAI,CAAC,OAAO;QAAE,OAAO;IACrB,OAAO,CAAC,GAAG,CAAC,kBAAkB,GAAG,OAAO,CAAC;AAC3C,CAAC"}
@@ -0,0 +1,31 @@
1
+ import { type Model } from "@earendil-works/pi-ai";
2
+ /**
3
+ * Resolves which provider:modelId the CLI talks to, plus the provenance for
4
+ * that decision (explicit flag, inferred from env, or built-in fallback). The
5
+ * shape lives in its own module so cli.ts stays focused on argv parsing and
6
+ * the I/O harness — provider list changes don't touch the CLI surface.
7
+ */
8
+ export interface ModelResolution {
9
+ modelName: string;
10
+ /** explicit: CLI flag; inferred: provider env var present; default: built-in fallback. */
11
+ source: "explicit" | "inferred" | "default";
12
+ /** Provider env var that triggered inference, e.g. "ANTHROPIC_API_KEY". */
13
+ envVar?: string;
14
+ /** True when the env var was loaded from <workdir>/.env rather than the shell. */
15
+ fromDotenv?: boolean;
16
+ }
17
+ export declare const DEFAULT_CLI_MODEL: string;
18
+ export declare const DEFAULT_CLI_MEMORY_MODEL: string;
19
+ export declare function resolveModelName(model: string): Model<any>;
20
+ /**
21
+ * Same selection logic as resolveCliModel, but picks each provider's cheaper
22
+ * observational-memory model.
23
+ */
24
+ export declare function resolveCliMemoryModel(memoryModelName: string | undefined, dotenvKeys: Set<string>): ModelResolution;
25
+ /**
26
+ * Resolve the user-visible model and report provenance so callers can show
27
+ * "inferred from ANTHROPIC_API_KEY in .env" etc.
28
+ */
29
+ export declare function resolveCliModel(modelName: string | undefined, dotenvKeys: Set<string>): ModelResolution;
30
+ export declare function describeModelResolution(resolution: ModelResolution): string;
31
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/model-resolution/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyB,KAAK,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAQ1E;;;;;GAKG;AAEH,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,0FAA0F;IAC1F,MAAM,EAAE,UAAU,GAAG,UAAU,GAAG,SAAS,CAAC;IAC5C,2EAA2E;IAC3E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kFAAkF;IAClF,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAiED,eAAO,MAAM,iBAAiB,QAAoC,CAAC;AACnE,eAAO,MAAM,wBAAwB,QAA2C,CAAC;AAEjF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,CAgB1D;AAUD;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,eAAe,EAAE,MAAM,GAAG,SAAS,EACnC,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,GACtB,eAAe,CAEjB;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,GACtB,eAAe,CAEjB;AA8BD,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,eAAe,GAAG,MAAM,CAO3E"}
@@ -0,0 +1,129 @@
1
+ import { findEnvKeys, getModel } from "@earendil-works/pi-ai";
2
+ import { DUET_GATEWAY_API_KEY_ENV, isDuetGatewayModelName, resolveDuetGatewayModel, } from "./duet-gateway.js";
3
+ /**
4
+ * Provider inference order. Entries are tried top-to-bottom; the first one
5
+ * with a present env var wins. `customEnvVar` covers providers pi-ai's
6
+ * `findEnvKeys` doesn't know about (currently only `duet-gateway`).
7
+ *
8
+ * `duet-gateway` sits before `vercel-ai-gateway` because the CLI startup shim
9
+ * copies `DUET_API_KEY` into `AI_GATEWAY_API_KEY`, which would otherwise route
10
+ * through Vercel's gateway directly when the user only set `DUET_API_KEY`.
11
+ */
12
+ const MODEL_PROVIDER_INFERENCE = [
13
+ {
14
+ provider: "anthropic",
15
+ model: "anthropic:claude-opus-4-7",
16
+ },
17
+ {
18
+ provider: "duet-gateway",
19
+ model: "duet-gateway:anthropic/claude-opus-4.7",
20
+ customEnvVar: () => (process.env[DUET_GATEWAY_API_KEY_ENV] ? DUET_GATEWAY_API_KEY_ENV : null),
21
+ },
22
+ {
23
+ provider: "vercel-ai-gateway",
24
+ model: "vercel-ai-gateway:anthropic/claude-opus-4.7",
25
+ },
26
+ {
27
+ provider: "openrouter",
28
+ model: "openrouter:anthropic/claude-opus-4.7",
29
+ },
30
+ {
31
+ provider: "openai",
32
+ model: "openai:gpt-5.5",
33
+ },
34
+ ];
35
+ const MEMORY_MODEL_PROVIDER_INFERENCE = [
36
+ {
37
+ provider: "anthropic",
38
+ model: "anthropic:claude-haiku-4-5",
39
+ },
40
+ {
41
+ provider: "duet-gateway",
42
+ model: "duet-gateway:anthropic/claude-haiku-4.5",
43
+ customEnvVar: () => (process.env[DUET_GATEWAY_API_KEY_ENV] ? DUET_GATEWAY_API_KEY_ENV : null),
44
+ },
45
+ {
46
+ provider: "vercel-ai-gateway",
47
+ model: "vercel-ai-gateway:anthropic/claude-haiku-4.5",
48
+ },
49
+ {
50
+ provider: "openrouter",
51
+ model: "openrouter:anthropic/claude-haiku-4.5",
52
+ },
53
+ {
54
+ provider: "openai",
55
+ model: "openai:gpt-5.4-mini",
56
+ },
57
+ ];
58
+ export const DEFAULT_CLI_MODEL = MODEL_PROVIDER_INFERENCE[0].model;
59
+ export const DEFAULT_CLI_MEMORY_MODEL = MEMORY_MODEL_PROVIDER_INFERENCE[0].model;
60
+ export function resolveModelName(model) {
61
+ const separator = model.indexOf(":");
62
+ if (separator === -1) {
63
+ throw new Error("Models must use provider:modelId syntax");
64
+ }
65
+ if (isDuetGatewayModelName(model)) {
66
+ const modelId = model.slice(separator + 1);
67
+ const resolved = resolveDuetGatewayModel(modelId);
68
+ if (!resolved) {
69
+ throw new Error(`Unknown duet-gateway model: ${modelId}`);
70
+ }
71
+ return resolved;
72
+ }
73
+ const provider = model.slice(0, separator);
74
+ const modelId = model.slice(separator + 1);
75
+ return getModel(provider, modelId);
76
+ }
77
+ function lookupProviderEnvVar(entry) {
78
+ if (entry.customEnvVar) {
79
+ return entry.customEnvVar() ?? undefined;
80
+ }
81
+ const envVars = findEnvKeys(entry.provider);
82
+ return envVars && envVars.length > 0 ? envVars[0] : undefined;
83
+ }
84
+ /**
85
+ * Same selection logic as resolveCliModel, but picks each provider's cheaper
86
+ * observational-memory model.
87
+ */
88
+ export function resolveCliMemoryModel(memoryModelName, dotenvKeys) {
89
+ return resolveCliModelWith(memoryModelName, MEMORY_MODEL_PROVIDER_INFERENCE, dotenvKeys);
90
+ }
91
+ /**
92
+ * Resolve the user-visible model and report provenance so callers can show
93
+ * "inferred from ANTHROPIC_API_KEY in .env" etc.
94
+ */
95
+ export function resolveCliModel(modelName, dotenvKeys) {
96
+ return resolveCliModelWith(modelName, MODEL_PROVIDER_INFERENCE, dotenvKeys);
97
+ }
98
+ function resolveCliModelWith(modelName, providerInference, dotenvKeys) {
99
+ if (modelName)
100
+ return { modelName, source: "explicit" };
101
+ const inferred = findInferredProviderEntry(providerInference);
102
+ if (inferred) {
103
+ return {
104
+ modelName: inferred.entry.model,
105
+ source: "inferred",
106
+ envVar: inferred.envVar,
107
+ fromDotenv: dotenvKeys.has(inferred.envVar),
108
+ };
109
+ }
110
+ return { modelName: providerInference[0].model, source: "default" };
111
+ }
112
+ function findInferredProviderEntry(providerInference) {
113
+ for (const entry of providerInference) {
114
+ const envVar = lookupProviderEnvVar(entry);
115
+ if (envVar)
116
+ return { entry, envVar };
117
+ }
118
+ return undefined;
119
+ }
120
+ export function describeModelResolution(resolution) {
121
+ if (resolution.source === "explicit")
122
+ return "explicit CLI flag";
123
+ if (resolution.source === "inferred") {
124
+ const where = resolution.fromDotenv ? "<workdir>/.env" : "shell environment";
125
+ return `inferred from ${resolution.envVar} in ${where}`;
126
+ }
127
+ return "built-in default (no provider env vars set)";
128
+ }
129
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/model-resolution/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ import type { TurnRunnerConfig } from "../types/config.js";
2
+ import type { TurnEvent, TurnMode, TurnOptions } from "../types/protocol.js";
3
+ import { Session, type SessionTurnRunner } from "./session.js";
4
+ export declare const DEFAULT_DUET_DIR = ".duet";
5
+ export declare const DEFAULT_DUET_HOME: string;
6
+ export declare const DEFAULT_SESSION_STORAGE_DIR: string;
7
+ export declare const DEFAULT_MEMORY_DB_PATH: string;
8
+ export interface SessionManagerCreateInput {
9
+ /** Optional fixed id; the manager generates one when omitted. */
10
+ sessionId?: string;
11
+ /** Routing mode for the new session. */
12
+ mode?: TurnMode;
13
+ /**
14
+ * When provided, the manager dispatches this prompt as the first turn after
15
+ * setup completes. Omit to leave the session idle until the caller sends a
16
+ * prompt directly.
17
+ */
18
+ prompt?: string;
19
+ options?: TurnOptions;
20
+ }
21
+ export interface SessionManagerOptions {
22
+ sessionStoragePath?: string;
23
+ createRunner?: (sessionId: string) => SessionTurnRunner;
24
+ }
25
+ export type SessionManagerEvent = {
26
+ sessionId: string;
27
+ event: TurnEvent;
28
+ };
29
+ export type SessionManagerEventHandler = (event: SessionManagerEvent) => void;
30
+ export declare class SessionManager {
31
+ private readonly options;
32
+ private readonly sessions;
33
+ private readonly eventHandlers;
34
+ private readonly sessionStoragePath;
35
+ readonly config: TurnRunnerConfig;
36
+ constructor(config: TurnRunnerConfig, options?: SessionManagerOptions);
37
+ subscribe(handler: SessionManagerEventHandler): () => void;
38
+ create(input: SessionManagerCreateInput): Session;
39
+ get(sessionId: string): Session | undefined;
40
+ resume(sessionId: string): Session;
41
+ dispose(): Promise<void>;
42
+ private createSession;
43
+ private emit;
44
+ }
45
+ //# sourceMappingURL=session-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-manager.d.ts","sourceRoot":"","sources":["../../../src/session/session-manager.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC7E,OAAO,EAAE,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAE/D,eAAO,MAAM,gBAAgB,UAAU,CAAC;AACxC,eAAO,MAAM,iBAAiB,QAAoC,CAAC;AACnE,eAAO,MAAM,2BAA2B,QAAsC,CAAC;AAC/E,eAAO,MAAM,sBAAsB,QAAuC,CAAC;AAE3E,MAAM,WAAW,yBAAyB;IACxC,iEAAiE;IACjE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wCAAwC;IACxC,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,WAAW,CAAC;CACvB;AAED,MAAM,WAAW,qBAAqB;IACpC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,YAAY,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,iBAAiB,CAAC;CACzD;AAED,MAAM,MAAM,mBAAmB,GAAG;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,SAAS,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG,CAAC,KAAK,EAAE,mBAAmB,KAAK,IAAI,CAAC;AAE9E,qBAAa,cAAc;IAQvB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAP1B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA8B;IACvD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAyC;IACvE,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAS;IAC5C,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC;gBAGhC,MAAM,EAAE,gBAAgB,EACP,OAAO,GAAE,qBAA0B;IAMtD,SAAS,CAAC,OAAO,EAAE,0BAA0B,GAAG,MAAM,IAAI;IAO1D,MAAM,CAAC,KAAK,EAAE,yBAAyB,GAAG,OAAO;IAkBjD,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS;IAI3C,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAQ5B,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAO9B,OAAO,CAAC,aAAa;IAgBrB,OAAO,CAAC,IAAI;CAKb"}