@wirecat/cli-core 0.498.0 → 0.500.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 (49) hide show
  1. package/CHANGELOG.md +67 -0
  2. package/dist/calendar/mcp/index.d.ts +12 -12
  3. package/dist/cli/messenger/hearing-command.js +1 -1
  4. package/dist/cli/messenger/models-command.js +2 -2
  5. package/dist/cli/messenger/transcribe-command.js +14 -10
  6. package/dist/cli/runs/command.js +2 -1
  7. package/dist/domain/knowledge.d.ts +1 -1
  8. package/dist/domain/knowledge.js +1 -1
  9. package/dist/entities/fact.d.ts +15 -1
  10. package/dist/entities/fact.js +6 -1
  11. package/dist/entities/fields.d.ts +11 -0
  12. package/dist/entities/fields.js +11 -0
  13. package/dist/entities/index.d.ts +25 -1
  14. package/dist/entities/memory.d.ts +14 -0
  15. package/dist/entities/memory.js +6 -1
  16. package/dist/errors/reasons.d.ts +1 -1
  17. package/dist/errors/reasons.js +8 -0
  18. package/dist/meetings/transcription.d.ts +5 -0
  19. package/dist/meetings/transcription.js +27 -6
  20. package/dist/speech/decode.d.ts +11 -1
  21. package/dist/speech/decode.js +20 -15
  22. package/dist/speech/hearing.d.ts +3 -1
  23. package/dist/speech/hearing.js +4 -4
  24. package/dist/speech/index.d.ts +5 -2
  25. package/dist/speech/index.js +4 -2
  26. package/dist/speech/local.d.ts +8 -0
  27. package/dist/speech/local.js +22 -1
  28. package/dist/speech/models.d.ts +2 -0
  29. package/dist/speech/models.js +2 -0
  30. package/dist/speech/openai.d.ts +54 -0
  31. package/dist/speech/openai.js +199 -0
  32. package/dist/speech/recognize.d.ts +25 -1
  33. package/dist/speech/recognize.js +52 -21
  34. package/dist/speech/transcribe.d.ts +25 -9
  35. package/dist/speech/transcribe.js +72 -13
  36. package/dist/speech/wav.d.ts +2 -0
  37. package/dist/speech/wav.js +20 -0
  38. package/dist/store/index.d.ts +1 -0
  39. package/dist/store/project-transfer/request.d.ts +1 -1
  40. package/dist/store/project-transfer/schema.d.ts +2 -2
  41. package/dist/store/project-transfer/snapshot-model.d.ts +2 -2
  42. package/dist/store/sqlite/evidence-sources.d.ts +23 -0
  43. package/dist/store/sqlite/evidence-sources.js +59 -0
  44. package/dist/store/sqlite/facts.d.ts +16 -0
  45. package/dist/store/sqlite/facts.js +39 -5
  46. package/dist/store/sqlite/memories.d.ts +28 -0
  47. package/dist/store/sqlite/memories.js +62 -3
  48. package/dist/store/sqlite/project-transfer/snapshot.d.ts +1 -1
  49. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -5,6 +5,73 @@ Notable changes to `@wirecat/cli-core` (`@wirecat/cli-messaging` up to 0.261.0,
5
5
  minor version may break callers, and says how under "Changed — may break callers". `pnpm docs:check` checks the
6
6
  shape of this file.
7
7
 
8
+ ## Unreleased
9
+
10
+ ## 0.500.0 — 31.10.2026
11
+
12
+ ### Added
13
+
14
+ - **A memory or fact can be forgotten for good.** `store.memories.remove(ref)` and `store.facts.remove(ref)` erase the
15
+ row, every link from or to it, its tags, and its words, pieces and vectors in the search indexes, in one write. The
16
+ words indexes are merged and freed pages zeroed (`secure_delete`), so the text is not left in the file; the
17
+ write-ahead log is emptied when no reader holds it. A record that replaced it no longer names it (`supersedes:
18
+ null`). Removing a fact also erases the soft-deleted memory it was migrated from in version 2, which still held its
19
+ text. Both answer `{ ref, removed: true, links }`, where `links` counts the links erased.
20
+ - **`store.facts.reject(ref)`** turns down a proposed fact: `FACT_STATUSES` gains `rejected`.
21
+ - **`store.memories.sources(ref)` and `store.facts.sources(ref)`** read each evidence link back as an `EvidenceSource`:
22
+ `ref`, `kind`, `title`, `sender`, `at`, `excerpt` (280 characters at most), `tool` and `missing`. A source deleted
23
+ since is still listed, `missing: true` with no excerpt, where `evidence` leaves it out; `ref` is `null` when its row
24
+ is gone from the store.
25
+ - **`Memory` and `Fact` carry `subjectName` and `subjectIsOwner`.** A person is named by their name, else the
26
+ owner's alias for them, else an identity's name; a project or organization by its name. The owner has no name in the
27
+ store, so `subjectName` is `null` and `subjectIsOwner` is `true`. The `memory` and `fact` entities gain optional
28
+ `subject_name`, `subject_is_owner` and `sources`.
29
+
30
+ ## 0.499.0 — 31.10.2026
31
+
32
+ ### Added
33
+
34
+ - **`decodeChannels(bytes)` in `@wirecat/cli-core/speech` returns every channel of a recording:**
35
+ `{ channels: Pcm[], mixed }`. A phone call recorded in stereo keeps one speaker per channel, and `decodeAudio`
36
+ keeps only the first, so the other speaker was lost. `decodeAudio` is unchanged and now exported too. Opus,
37
+ Vorbis, FLAC and MP3 keep their channels apart; a format only ffmpeg reads arrives as one channel with
38
+ `mixed: true`, so a caller can tell a mixed-down call from a mono one.
39
+ - **OpenAI transcription: `transcribeOpenAI(pcm, { apiKey, model, languages, prompt, keywords })`.** It sends one
40
+ channel to OpenAI's `/audio/transcriptions` (`gpt-transcribe` by default, `languages[]` and `keywords[]` as
41
+ repeated fields, no SDK) and answers `[{ start, end, text }]` in seconds: one piece per stretch of speech the
42
+ voice detector found, each sent alone, so two channels merge into a dialogue by `start`. Two stretches the
43
+ detector split only because speech ran past 20 seconds stay one piece. `gpt-transcribe` gives no timestamps, so
44
+ the times are the detector's: about 0.1–0.3 s late at the start and 0.5–0.8 s late at the end, and very quiet
45
+ speech is missed, as it is locally. `bundle: true` trades the turns for fewer requests: up to ten minutes
46
+ (`LONGEST_REQUEST_SECONDS`) in one. It needs the voice detector file that comes with any speech model
47
+ (`models download`), except bundled audio of up to ten minutes. A 429 or a server error is tried again, waiting
48
+ as long as `Retry-After` asks; errors carry `auth.failed` (401), `access.denied` (403, which OpenAI also answers
49
+ for an unsupported country), `transcription.quota-exhausted` (credit, spend or usage limit; never retried),
50
+ `transcription.no-key`, `transcription.too-large`, `provider.rate-limited` or `provider.unavailable`, and never
51
+ the key. A keyword with `<`, `>` or a line break is refused before sending.
52
+ - **`recognizeLocalPieces(model, pcm)` gives the same timed pieces from a local model**, one per stretch of speech
53
+ the voice detector cut.
54
+ - **`transcribeWith: "openai"` sends voice messages to OpenAI**, with the key `models keys set openai` or
55
+ `OPENAI_API_KEY` holds and the model in the profile's `transcribeModel` (`gpt-transcribe` when unset). Only when
56
+ named: `auto` never sends audio off the machine, and a read-only process refuses. A transcript heard this way is
57
+ kept as `openai:<model>`.
58
+ - **Meeting transcription keeps who spoke.** `MeetingRecognitionSegment.speaker` (trimmed; `null` is none) is stored
59
+ as the row's speaker, and segments of different speakers may overlap — two people on a call talk over each
60
+ other. One speaker's own segments still may not, and segments without a speaker are checked as before. A
61
+ transcript whose `recognition.engine` is `openai` is stored as `openai/<model>`, format `openai-transcription`;
62
+ local transcripts keep `local/<engine>/<model>` exactly.
63
+
64
+ ### Changed — may break callers
65
+
66
+ - **An unknown `transcribeWith` in a profile now refuses to transcribe** with `validation_error`, naming the four
67
+ values. Before, any value other than `local` silently meant asking the messenger first. `models list` and
68
+ `models download` still read such a profile. Set it to `auto`, `messenger`, `local` or `openai`.
69
+
70
+ ### Fixed
71
+
72
+ - **`runs list` with nothing recorded no longer says a run is kept only with `--record`.** Every command that does
73
+ its work is kept by default; `record: false` in the config keeps failures only, and `--no-record` keeps nothing.
74
+
8
75
  ## 0.497.0 — 31.10.2026
9
76
 
10
77
  ### Added
@@ -10,13 +10,13 @@ export declare const calendarTools: ({
10
10
  inputSchema: {
11
11
  type: string;
12
12
  properties: {
13
+ limit?: undefined;
13
14
  account_id: {
14
15
  type: string;
15
16
  minimum: number;
16
17
  };
17
18
  words?: undefined;
18
19
  timezone?: undefined;
19
- limit?: undefined;
20
20
  event?: undefined;
21
21
  } | {
22
22
  account_id: {
@@ -38,9 +38,9 @@ export declare const calendarTools: ({
38
38
  };
39
39
  event?: undefined;
40
40
  } | {
41
+ limit?: undefined;
41
42
  words?: undefined;
42
43
  timezone?: undefined;
43
- limit?: undefined;
44
44
  event: {
45
45
  type: string;
46
46
  minLength: number;
@@ -50,9 +50,9 @@ export declare const calendarTools: ({
50
50
  minimum: number;
51
51
  };
52
52
  } | {
53
+ limit?: undefined;
53
54
  words?: undefined;
54
55
  timezone?: undefined;
55
- limit?: undefined;
56
56
  event?: undefined;
57
57
  account_id?: undefined;
58
58
  };
@@ -71,13 +71,13 @@ export declare const calendarTools: ({
71
71
  inputSchema: {
72
72
  type: string;
73
73
  properties: {
74
+ limit?: undefined;
74
75
  account_id: {
75
76
  type: string;
76
77
  minimum: number;
77
78
  };
78
79
  words?: undefined;
79
80
  timezone?: undefined;
80
- limit?: undefined;
81
81
  event?: undefined;
82
82
  } | {
83
83
  account_id: {
@@ -99,9 +99,9 @@ export declare const calendarTools: ({
99
99
  };
100
100
  event?: undefined;
101
101
  } | {
102
+ limit?: undefined;
102
103
  words?: undefined;
103
104
  timezone?: undefined;
104
- limit?: undefined;
105
105
  event: {
106
106
  type: string;
107
107
  minLength: number;
@@ -111,9 +111,9 @@ export declare const calendarTools: ({
111
111
  minimum: number;
112
112
  };
113
113
  } | {
114
+ limit?: undefined;
114
115
  words?: undefined;
115
116
  timezone?: undefined;
116
- limit?: undefined;
117
117
  event?: undefined;
118
118
  account_id?: undefined;
119
119
  };
@@ -132,13 +132,13 @@ export declare const calendarTools: ({
132
132
  inputSchema: {
133
133
  type: string;
134
134
  properties: {
135
+ limit?: undefined;
135
136
  account_id: {
136
137
  type: string;
137
138
  minimum: number;
138
139
  };
139
140
  words?: undefined;
140
141
  timezone?: undefined;
141
- limit?: undefined;
142
142
  event?: undefined;
143
143
  } | {
144
144
  account_id: {
@@ -160,9 +160,9 @@ export declare const calendarTools: ({
160
160
  };
161
161
  event?: undefined;
162
162
  } | {
163
+ limit?: undefined;
163
164
  words?: undefined;
164
165
  timezone?: undefined;
165
- limit?: undefined;
166
166
  event: {
167
167
  type: string;
168
168
  minLength: number;
@@ -172,9 +172,9 @@ export declare const calendarTools: ({
172
172
  minimum: number;
173
173
  };
174
174
  } | {
175
+ limit?: undefined;
175
176
  words?: undefined;
176
177
  timezone?: undefined;
177
- limit?: undefined;
178
178
  event?: undefined;
179
179
  account_id?: undefined;
180
180
  };
@@ -193,13 +193,13 @@ export declare const calendarTools: ({
193
193
  inputSchema: {
194
194
  type: string;
195
195
  properties: {
196
+ limit?: undefined;
196
197
  account_id: {
197
198
  type: string;
198
199
  minimum: number;
199
200
  };
200
201
  words?: undefined;
201
202
  timezone?: undefined;
202
- limit?: undefined;
203
203
  event?: undefined;
204
204
  } | {
205
205
  account_id: {
@@ -221,9 +221,9 @@ export declare const calendarTools: ({
221
221
  };
222
222
  event?: undefined;
223
223
  } | {
224
+ limit?: undefined;
224
225
  words?: undefined;
225
226
  timezone?: undefined;
226
- limit?: undefined;
227
227
  event: {
228
228
  type: string;
229
229
  minLength: number;
@@ -233,9 +233,9 @@ export declare const calendarTools: ({
233
233
  minimum: number;
234
234
  };
235
235
  } | {
236
+ limit?: undefined;
236
237
  words?: undefined;
237
238
  timezone?: undefined;
238
- limit?: undefined;
239
239
  event?: undefined;
240
240
  account_id?: undefined;
241
241
  };
@@ -23,7 +23,7 @@ export const hearForCommand = async (context, messenger, messages, transcribe, m
23
23
  const hearing = await hearVoices(messenger, messages, kept, transcribe && !offline
24
24
  ? {
25
25
  choice: {
26
- ...choose(messenger, context.settings, model === undefined ? {} : { model }, context.env),
26
+ ...choose(messenger, context.settings, model === undefined ? {} : { model }, context.env, context.keyring),
27
27
  ...(context.recognizer ? { open: context.recognizer } : {}),
28
28
  },
29
29
  connect: connect ?? ((work) => context.withMessenger(work)),
@@ -89,7 +89,7 @@ const downloadAudioModel = async (command, messenger, id) => {
89
89
  finally {
90
90
  recognizer.free();
91
91
  }
92
- const chosen = choose(messenger, context.settings, {}, context.env).model.id;
92
+ const chosen = choose(messenger, context.settings, {}, context.env, context.keyring).model.id;
93
93
  renderAnswer(command, context, itemOf(audioItem(model, directory, chosen)), downloaded);
94
94
  }, { unbounded: true });
95
95
  };
@@ -174,7 +174,7 @@ export const modelsCommand = (messenger) => {
174
174
  const rerankers = kinds === undefined || kinds === "reranker"
175
175
  ? RERANK_MODELS.filter((model) => id === undefined || model.id === id)
176
176
  : [];
177
- const chosen = audioModels.length > 0 ? choose(messenger, context.settings, {}, context.env).model.id : "";
177
+ const chosen = audioModels.length > 0 ? choose(messenger, context.settings, {}, context.env, context.keyring).model.id : "";
178
178
  const catalogue = [
179
179
  ...audioModels.map((model) => audioItem(model, modelsDirectory(context.env), chosen)),
180
180
  ...textModels.map((model) => textItem(model, textModelsDirectory(context.env))),
@@ -1,7 +1,8 @@
1
1
  import { annotate } from "@wirecat/cli-base/commands";
2
2
  import { openKept } from "../../speech/hearing.js";
3
3
  import { isInstalled } from "../../speech/install.js";
4
- import { choose, hearLocally, hearOnline, notDownloaded } from "../../speech/transcribe.js";
4
+ import { choose, heardVia, hearLocally, hearOnline, keptSource, notDownloaded, } from "../../speech/transcribe.js";
5
+ import { environmentOf } from "../context.js";
5
6
  import { REMOTE_READ } from "../effects.js";
6
7
  import { renderAnswer } from "../envelope.js";
7
8
  import { messengerContext } from "./context.js";
@@ -22,10 +23,13 @@ export const transcribeSubcommand = (messages, messenger) => annotate(messages.c
22
23
  .action(async function (chat, messageId) {
23
24
  const context = messengerContext(this, messenger);
24
25
  const choice = {
25
- ...choose(messenger, context.settings, this.opts(), context.env),
26
+ ...choose(messenger, context.settings, this.opts(), context.env, context.keyring),
26
27
  ...(context.recognizer ? { open: context.recognizer } : {}),
28
+ ...signalOf(this),
27
29
  };
28
- // Before connecting: a missing model should not cost a login.
30
+ // Before connecting: a missing model or OpenAI key should not cost a login.
31
+ if (choice.refusal)
32
+ throw choice.refusal;
29
33
  if (choice.with === "local" && !isInstalled(choice.model, choice.directory)) {
30
34
  throw notDownloaded(messenger, choice.model);
31
35
  }
@@ -51,17 +55,17 @@ export const transcribeSubcommand = (messages, messenger) => annotate(messages.c
51
55
  return [resolved, undefined, await hearOnline(messenger, connection, resolved, id, choice, read)];
52
56
  });
53
57
  const heard = before
54
- ? {
55
- messageId: id,
56
- text: before.text,
57
- pending: false,
58
- ...(before.source === messenger.provider ? { via: before.source } : { via: "local", model: before.source }),
59
- }
58
+ ? { messageId: id, text: before.text, pending: false, ...heardVia(before.source, messenger.provider) }
60
59
  : online instanceof Uint8Array
61
60
  ? await hearLocally(online, id, choice)
62
61
  : online;
63
62
  if (!heard.pending && !before) {
64
- await withKept((kept) => kept.keep({ chatId, messageId: id }, heard.text, heard.model ?? heard.via));
63
+ await withKept((kept) => kept.keep({ chatId, messageId: id }, heard.text, keptSource(heard)));
65
64
  }
66
65
  renderAnswer(this, context, heardAnswer(heard, chatId), () => `${heard.text}\n`);
67
66
  });
67
+ const signalOf = (command) => {
68
+ const { signal, commandSignal } = environmentOf(command);
69
+ const signals = [signal, commandSignal].filter((one) => one !== undefined);
70
+ return signals.length ? { signal: AbortSignal.any(signals) } : {};
71
+ };
@@ -41,7 +41,8 @@ export const runsCommand = (app) => {
41
41
  args: words.length ? { query: typedQuery(words) } : {},
42
42
  }));
43
43
  if (runs.length === 0)
44
- renderer.note("nothing recorded — a run is kept with `--record`, or when it fails");
44
+ renderer.note("nothing recorded — a command that does its work is kept unless the config says `record: false` (then only " +
45
+ "failures) or it ran with `--no-record`");
45
46
  });
46
47
  annotate(command.command("show"), {
47
48
  examples: [`${app.command} runs show run-101`],
@@ -1,5 +1,5 @@
1
1
  export declare const FACT_TYPES: readonly ["fact", "statement", "question", "decision", "promise"];
2
- export declare const FACT_STATUSES: readonly ["proposed", "accepted", "superseded", "reversed"];
2
+ export declare const FACT_STATUSES: readonly ["proposed", "accepted", "superseded", "reversed", "rejected"];
3
3
  export declare const MEMORY_KINDS: readonly ["summary", "digest", "preference"];
4
4
  export declare const MEMORY_STATUSES: readonly ["proposed", "confirmed", "stale", "superseded"];
5
5
  export declare const MEMORY_SCOPES: readonly ["personal", "work"];
@@ -1,6 +1,6 @@
1
1
  import { TASK_KINDS } from "../tasks/index.js";
2
2
  export const FACT_TYPES = ["fact", "statement", "question", "decision", "promise"];
3
- export const FACT_STATUSES = ["proposed", "accepted", "superseded", "reversed"];
3
+ export const FACT_STATUSES = ["proposed", "accepted", "superseded", "reversed", "rejected"];
4
4
  export const MEMORY_KINDS = ["summary", "digest", "preference"];
5
5
  export const MEMORY_STATUSES = ["proposed", "confirmed", "stale", "superseded"];
6
6
  export const MEMORY_SCOPES = ["personal", "work"];
@@ -4,9 +4,12 @@ export declare const fact: v.StrictObjectSchema<{
4
4
  readonly id: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>;
5
5
  readonly kind: v.PicklistSchema<readonly ["fact", "statement", "question", "decision", "promise"], undefined>;
6
6
  readonly text: v.StringSchema<undefined>;
7
- readonly status: v.PicklistSchema<readonly ["proposed", "accepted", "superseded", "reversed"], undefined>;
7
+ readonly status: v.PicklistSchema<readonly ["proposed", "accepted", "superseded", "reversed", "rejected"], undefined>;
8
8
  readonly project: v.NullableSchema<v.StringSchema<undefined>, undefined>;
9
9
  readonly subject: v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, "a reference such as `note:42`">]>, undefined>;
10
+ /** What the subject is called; `null` for the owner and for a row with no name. */
11
+ readonly subject_name: v.OptionalSchema<v.NullableSchema<v.StringSchema<undefined>, undefined>, undefined>;
12
+ readonly subject_is_owner: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
10
13
  readonly occurred_at: v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>, undefined>;
11
14
  readonly supersedes: v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, "a reference such as `note:42`">]>, undefined>;
12
15
  readonly author: v.StrictObjectSchema<{
@@ -24,6 +27,17 @@ export declare const fact: v.StrictObjectSchema<{
24
27
  /** Who recorded it: the owner, or an agent whose fact waits as proposed. */
25
28
  readonly origin: v.PicklistSchema<["owner", "agent"], undefined>;
26
29
  readonly evidence: v.ArraySchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, "a reference such as `note:42`">]>, undefined>;
30
+ /** With `--sources`: each piece of evidence read back. */
31
+ readonly sources: v.OptionalSchema<v.ArraySchema<v.StrictObjectSchema<{
32
+ readonly ref: v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, "a reference such as `note:42`">]>, undefined>;
33
+ readonly kind: v.StringSchema<undefined>;
34
+ readonly title: v.NullableSchema<v.StringSchema<undefined>, undefined>;
35
+ readonly sender: v.NullableSchema<v.StringSchema<undefined>, undefined>;
36
+ readonly at: v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>, undefined>;
37
+ readonly excerpt: v.NullableSchema<v.StringSchema<undefined>, undefined>;
38
+ readonly tool: v.NullableSchema<v.StringSchema<undefined>, undefined>;
39
+ readonly missing: v.BooleanSchema<undefined>;
40
+ }, undefined>, undefined>, undefined>;
27
41
  readonly created_at: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>;
28
42
  readonly updated_at: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>;
29
43
  }, undefined>;
@@ -1,6 +1,6 @@
1
1
  import * as v from "valibot";
2
2
  import { FACT_STATUSES, FACT_TYPES, MEMORY_SCOPES } from "../domain/knowledge.js";
3
- import { author, id, reference, text, time } from "./fields.js";
3
+ import { author, evidenceSource, id, reference, text, time } from "./fields.js";
4
4
  export const fact = v.strictObject({
5
5
  ref: reference,
6
6
  id,
@@ -9,6 +9,9 @@ export const fact = v.strictObject({
9
9
  status: v.picklist(FACT_STATUSES),
10
10
  project: v.nullable(text),
11
11
  subject: v.nullable(reference),
12
+ /** What the subject is called; `null` for the owner and for a row with no name. */
13
+ subject_name: v.optional(v.nullable(text)),
14
+ subject_is_owner: v.optional(v.boolean()),
12
15
  occurred_at: v.nullable(time),
13
16
  supersedes: v.nullable(reference),
14
17
  author,
@@ -19,6 +22,8 @@ export const fact = v.strictObject({
19
22
  /** Who recorded it: the owner, or an agent whose fact waits as proposed. */
20
23
  origin: v.picklist(["owner", "agent"]),
21
24
  evidence: v.array(reference),
25
+ /** With `--sources`: each piece of evidence read back. */
26
+ sources: v.optional(v.array(evidenceSource)),
22
27
  created_at: time,
23
28
  updated_at: time,
24
29
  });
@@ -10,6 +10,17 @@ export declare const count: v.SchemaWithPipe<readonly [v.NumberSchema<undefined>
10
10
  /** Fields of an answer item someone other than the owner wrote, as dotted paths: an agent reads them as data. */
11
11
  export declare const untrusted: v.OptionalSchema<v.ArraySchema<v.StringSchema<undefined>, undefined>, undefined>;
12
12
  export declare const providerMetadata: v.OptionalSchema<v.RecordSchema<v.StringSchema<undefined>, v.UnknownSchema, undefined>, undefined>;
13
+ /** A reference a memory or fact rests on, read back; `missing` once it was deleted since. */
14
+ export declare const evidenceSource: v.StrictObjectSchema<{
15
+ readonly ref: v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, "a reference such as `note:42`">]>, undefined>;
16
+ readonly kind: v.StringSchema<undefined>;
17
+ readonly title: v.NullableSchema<v.StringSchema<undefined>, undefined>;
18
+ readonly sender: v.NullableSchema<v.StringSchema<undefined>, undefined>;
19
+ readonly at: v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>, undefined>;
20
+ readonly excerpt: v.NullableSchema<v.StringSchema<undefined>, undefined>;
21
+ readonly tool: v.NullableSchema<v.StringSchema<undefined>, undefined>;
22
+ readonly missing: v.BooleanSchema<undefined>;
23
+ }, undefined>;
13
24
  export declare const author: v.StrictObjectSchema<{
14
25
  readonly type: v.PicklistSchema<["person", "bot"], undefined>;
15
26
  readonly id: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>;
@@ -10,6 +10,17 @@ export const count = v.pipe(v.number(), v.integer(), v.minValue(0));
10
10
  /** Fields of an answer item someone other than the owner wrote, as dotted paths: an agent reads them as data. */
11
11
  export const untrusted = v.optional(v.array(text));
12
12
  export const providerMetadata = v.optional(v.record(v.string(), v.unknown()));
13
+ /** A reference a memory or fact rests on, read back; `missing` once it was deleted since. */
14
+ export const evidenceSource = v.strictObject({
15
+ ref: v.nullable(reference),
16
+ kind: text,
17
+ title: v.nullable(text),
18
+ sender: v.nullable(text),
19
+ at: v.nullable(time),
20
+ excerpt: v.nullable(text),
21
+ tool: v.nullable(text),
22
+ missing: v.boolean(),
23
+ });
13
24
  export const author = v.strictObject({
14
25
  type: v.picklist(["person", "bot"]),
15
26
  id,
@@ -5340,9 +5340,11 @@ export declare const ENTITIES: {
5340
5340
  readonly id: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>;
5341
5341
  readonly kind: v.PicklistSchema<readonly ["fact", "statement", "question", "decision", "promise"], undefined>;
5342
5342
  readonly text: v.StringSchema<undefined>;
5343
- readonly status: v.PicklistSchema<readonly ["proposed", "accepted", "superseded", "reversed"], undefined>;
5343
+ readonly status: v.PicklistSchema<readonly ["proposed", "accepted", "superseded", "reversed", "rejected"], undefined>;
5344
5344
  readonly project: v.NullableSchema<v.StringSchema<undefined>, undefined>;
5345
5345
  readonly subject: v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, "a reference such as `note:42`">]>, undefined>;
5346
+ readonly subject_name: v.OptionalSchema<v.NullableSchema<v.StringSchema<undefined>, undefined>, undefined>;
5347
+ readonly subject_is_owner: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
5346
5348
  readonly occurred_at: v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>, undefined>;
5347
5349
  readonly supersedes: v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, "a reference such as `note:42`">]>, undefined>;
5348
5350
  readonly author: v.StrictObjectSchema<{
@@ -5358,6 +5360,16 @@ export declare const ENTITIES: {
5358
5360
  readonly scope: v.NullableSchema<v.PicklistSchema<readonly ["personal", "work"], undefined>, undefined>;
5359
5361
  readonly origin: v.PicklistSchema<["owner", "agent"], undefined>;
5360
5362
  readonly evidence: v.ArraySchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, "a reference such as `note:42`">]>, undefined>;
5363
+ readonly sources: v.OptionalSchema<v.ArraySchema<v.StrictObjectSchema<{
5364
+ readonly ref: v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, "a reference such as `note:42`">]>, undefined>;
5365
+ readonly kind: v.StringSchema<undefined>;
5366
+ readonly title: v.NullableSchema<v.StringSchema<undefined>, undefined>;
5367
+ readonly sender: v.NullableSchema<v.StringSchema<undefined>, undefined>;
5368
+ readonly at: v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>, undefined>;
5369
+ readonly excerpt: v.NullableSchema<v.StringSchema<undefined>, undefined>;
5370
+ readonly tool: v.NullableSchema<v.StringSchema<undefined>, undefined>;
5371
+ readonly missing: v.BooleanSchema<undefined>;
5372
+ }, undefined>, undefined>, undefined>;
5361
5373
  readonly created_at: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>;
5362
5374
  readonly updated_at: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>;
5363
5375
  }, undefined>;
@@ -5367,6 +5379,8 @@ export declare const ENTITIES: {
5367
5379
  readonly kind: v.PicklistSchema<readonly ["summary", "digest", "preference"], undefined>;
5368
5380
  readonly text: v.StringSchema<undefined>;
5369
5381
  readonly subject: v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, "a reference such as `note:42`">]>, undefined>;
5382
+ readonly subject_name: v.OptionalSchema<v.NullableSchema<v.StringSchema<undefined>, undefined>, undefined>;
5383
+ readonly subject_is_owner: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
5370
5384
  readonly author: v.StrictObjectSchema<{
5371
5385
  readonly type: v.PicklistSchema<["person", "bot"], undefined>;
5372
5386
  readonly id: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>;
@@ -5378,6 +5392,16 @@ export declare const ENTITIES: {
5378
5392
  readonly scope: v.PicklistSchema<readonly ["personal", "work"], undefined>;
5379
5393
  readonly supersedes: v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, "a reference such as `note:42`">]>, undefined>;
5380
5394
  readonly evidence: v.ArraySchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, "a reference such as `note:42`">]>, undefined>;
5395
+ readonly sources: v.OptionalSchema<v.ArraySchema<v.StrictObjectSchema<{
5396
+ readonly ref: v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, "a reference such as `note:42`">]>, undefined>;
5397
+ readonly kind: v.StringSchema<undefined>;
5398
+ readonly title: v.NullableSchema<v.StringSchema<undefined>, undefined>;
5399
+ readonly sender: v.NullableSchema<v.StringSchema<undefined>, undefined>;
5400
+ readonly at: v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>, undefined>;
5401
+ readonly excerpt: v.NullableSchema<v.StringSchema<undefined>, undefined>;
5402
+ readonly tool: v.NullableSchema<v.StringSchema<undefined>, undefined>;
5403
+ readonly missing: v.BooleanSchema<undefined>;
5404
+ }, undefined>, undefined>, undefined>;
5381
5405
  readonly last_verified_at: v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>, undefined>;
5382
5406
  readonly created_at: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>;
5383
5407
  readonly updated_at: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>;
@@ -5,6 +5,9 @@ export declare const memory: v.StrictObjectSchema<{
5
5
  readonly kind: v.PicklistSchema<readonly ["summary", "digest", "preference"], undefined>;
6
6
  readonly text: v.StringSchema<undefined>;
7
7
  readonly subject: v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, "a reference such as `note:42`">]>, undefined>;
8
+ /** What the subject is called; `null` for the owner and for a row with no name. */
9
+ readonly subject_name: v.OptionalSchema<v.NullableSchema<v.StringSchema<undefined>, undefined>, undefined>;
10
+ readonly subject_is_owner: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
8
11
  readonly author: v.StrictObjectSchema<{
9
12
  readonly type: v.PicklistSchema<["person", "bot"], undefined>;
10
13
  readonly id: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>]>;
@@ -16,6 +19,17 @@ export declare const memory: v.StrictObjectSchema<{
16
19
  readonly scope: v.PicklistSchema<readonly ["personal", "work"], undefined>;
17
20
  readonly supersedes: v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, "a reference such as `note:42`">]>, undefined>;
18
21
  readonly evidence: v.ArraySchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, "a reference such as `note:42`">]>, undefined>;
22
+ /** With `--sources`: each piece of evidence read back. */
23
+ readonly sources: v.OptionalSchema<v.ArraySchema<v.StrictObjectSchema<{
24
+ readonly ref: v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, "a reference such as `note:42`">]>, undefined>;
25
+ readonly kind: v.StringSchema<undefined>;
26
+ readonly title: v.NullableSchema<v.StringSchema<undefined>, undefined>;
27
+ readonly sender: v.NullableSchema<v.StringSchema<undefined>, undefined>;
28
+ readonly at: v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>, undefined>;
29
+ readonly excerpt: v.NullableSchema<v.StringSchema<undefined>, undefined>;
30
+ readonly tool: v.NullableSchema<v.StringSchema<undefined>, undefined>;
31
+ readonly missing: v.BooleanSchema<undefined>;
32
+ }, undefined>, undefined>, undefined>;
19
33
  readonly last_verified_at: v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>, undefined>;
20
34
  readonly created_at: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>;
21
35
  readonly updated_at: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.IsoTimestampAction<string, "an ISO 8601 time in UTC">, v.EndsWithAction<string, "Z", "an ISO 8601 time in UTC, ending in `Z`">]>;
@@ -1,12 +1,15 @@
1
1
  import * as v from "valibot";
2
2
  import { MEMORY_KINDS, MEMORY_SCOPES, MEMORY_STATUSES } from "../domain/knowledge.js";
3
- import { author, id, reference, text, time } from "./fields.js";
3
+ import { author, evidenceSource, id, reference, text, time } from "./fields.js";
4
4
  export const memory = v.strictObject({
5
5
  ref: reference,
6
6
  id,
7
7
  kind: v.picklist(MEMORY_KINDS),
8
8
  text,
9
9
  subject: v.nullable(reference),
10
+ /** What the subject is called; `null` for the owner and for a row with no name. */
11
+ subject_name: v.optional(v.nullable(text)),
12
+ subject_is_owner: v.optional(v.boolean()),
10
13
  author,
11
14
  model: v.nullable(text),
12
15
  confidence: v.nullable(v.number()),
@@ -14,6 +17,8 @@ export const memory = v.strictObject({
14
17
  scope: v.picklist(MEMORY_SCOPES),
15
18
  supersedes: v.nullable(reference),
16
19
  evidence: v.array(reference),
20
+ /** With `--sources`: each piece of evidence read back. */
21
+ sources: v.optional(v.array(evidenceSource)),
17
22
  last_verified_at: v.nullable(time),
18
23
  created_at: time,
19
24
  updated_at: time,
@@ -7,7 +7,7 @@ export declare const REASONS: ErrorReason[];
7
7
  * Detail keys an error from this package may carry, until each is registered on its own reason. Not `cause`:
8
8
  * that can hold a provider's or SQLite's raw text.
9
9
  */
10
- export declare const DETAILS: readonly ["contracts", "calendars", "allowed", "alternative", "arguments", "at", "available", "batch", "budget", "built", "candidates", "chat", "chat_id", "cli", "complete", "emitted_bytes", "exact", "forum", "guide", "hint", "id", "index", "kind", "limit", "limit_source", "max_bytes", "model", "name", "operation_id", "operation_ids", "text_limit", "store_refused_in", "partial_output", "path", "permission", "person_ids", "previous_chat_id", "profiles", "provider_error", "provider", "recovery", "reference", "remembered", "retry_at", "runtime", "saved", "scheduled_for", "script", "sent", "sent_count", "settlement_failed", "span", "sqlite", "stage", "standing", "state", "stderr", "term", "total", "upgraded", "wanted"];
10
+ export declare const DETAILS: readonly ["contracts", "calendars", "allowed", "alternative", "arguments", "at", "available", "batch", "budget", "built", "candidates", "chat", "chat_id", "cli", "complete", "emitted_bytes", "exact", "forum", "guide", "hint", "id", "index", "kind", "limit", "limit_source", "max_bytes", "model", "name", "operation_id", "operation_ids", "text_limit", "store_refused_in", "partial_output", "path", "permission", "person_ids", "previous_chat_id", "profiles", "provider_error", "provider", "recovery", "reference", "remembered", "retry_at", "retry_after_ms", "runtime", "saved", "scheduled_for", "script", "sent", "sent_count", "settlement_failed", "span", "sqlite", "stage", "standing", "state", "stderr", "term", "total", "upgraded", "wanted"];
11
11
  /** What a CLI adds to the shared registry: its own reasons, and the detail keys its adapters raise. */
12
12
  export interface AppErrors {
13
13
  reasons?: readonly ErrorReason[];
@@ -88,6 +88,13 @@ const OTHERS = [
88
88
  validation("memory.evidence-required", "a memory needs its evidence"),
89
89
  validation("memory.scope-required", "a memory needs its scope"),
90
90
  ["model.not-downloaded", "not_found", "the model is not downloaded on this machine"],
91
+ ["transcription.no-key", "authentication_error", "no OpenAI key is set for transcription"],
92
+ validation("transcription.too-large", "the audio is over the transcription provider's size limit"),
93
+ [
94
+ "transcription.quota-exhausted",
95
+ "permission_error",
96
+ "the transcription provider account has no credit or limit left",
97
+ ],
91
98
  validation("name.invalid", "the name is not valid"),
92
99
  validation("output.choose-fields", "at a terminal, --json names the fields it prints"),
93
100
  validation("output.one-object", "a report is one JSON object; --jsonl streams lists only"),
@@ -201,6 +208,7 @@ export const DETAILS = [
201
208
  "reference",
202
209
  "remembered",
203
210
  "retry_at",
211
+ "retry_after_ms",
204
212
  "runtime",
205
213
  "saved",
206
214
  "scheduled_for",
@@ -19,6 +19,11 @@ export interface MeetingRecognitionSegment {
19
19
  startMs: number;
20
20
  endMs: number;
21
21
  text: string;
22
+ /**
23
+ * Who spoke, when the source knows — a channel of a two-channel call. Speakers may overlap; one speaker may not.
24
+ * Trimmed; `null` is no speaker.
25
+ */
26
+ speaker?: string | null;
22
27
  }
23
28
  export interface MeetingTranscriptionContext {
24
29
  maxBytes: number;