faces-cli 1.7.2 → 1.7.4

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.
@@ -15,7 +15,7 @@ export default class ChatChat extends BaseCommand {
15
15
  ...BaseCommand.baseFlags,
16
16
  message: Flags.string({ char: 'm', description: 'User message (repeatable)', multiple: true, required: false }),
17
17
  llm: Flags.string({ description: 'LLM override (e.g. gpt-4o-mini, claude-sonnet-4-6)' }),
18
- formula: Flags.string({ description: 'Compose a run-time composite from your own faces, e.g. "socrates | nietzsche" (operators: | & ^ -). Requires --llm.' }),
18
+ formula: Flags.string({ description: 'Compose a run-time composite from your own faces, e.g. "socrates | nietzsche" (operators: | & ^ -). Requires --llm. The composite takes the name of its first operand; use face:create --formula for a named, persisted composite.' }),
19
19
  system: Flags.string({ description: 'System prompt / instructions' }),
20
20
  stream: Flags.boolean({ description: 'Stream the response', default: false }),
21
21
  'max-tokens': Flags.integer({ description: 'Max tokens' }),
@@ -10,6 +10,8 @@ export default class FaceCreate extends BaseCommand {
10
10
  formula: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
11
11
  attr: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
12
12
  tool: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
13
+ 'profile-addendum': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
14
+ 'profile-addendum-file': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
13
15
  'base-url': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
14
16
  token: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
15
17
  'api-key': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
@@ -2,7 +2,7 @@ import { Flags } from '@oclif/core';
2
2
  import { BaseCommand } from '../../base.js';
3
3
  import { FacesAPIError } from '../../client.js';
4
4
  import { CatalogService } from '../../catalog.js';
5
- import { renameFaceFields } from '../../utils.js';
5
+ import { renameFaceFields, resolveProfileAddendum } from '../../utils.js';
6
6
  export default class FaceCreate extends BaseCommand {
7
7
  static description = 'Create a new face';
8
8
  static flags = {
@@ -15,6 +15,8 @@ export default class FaceCreate extends BaseCommand {
15
15
  formula: Flags.string({ description: 'Boolean formula over owned concrete face aliases (e.g. "a | b", "(a | b) - c"). Creates a composite face.' }),
16
16
  attr: Flags.string({ description: 'Attribute KEY=VALUE (repeatable)', multiple: true }),
17
17
  tool: Flags.string({ description: 'Tool name to enable (repeatable)', multiple: true }),
18
+ 'profile-addendum': Flags.string({ description: 'Per-face system prompt, injected after the persona profile and before any per-request system prompt (max 100,000 chars).' }),
19
+ 'profile-addendum-file': Flags.string({ description: 'Read the per-face system prompt from a file (alternative to --profile-addendum).', exclusive: ['profile-addendum'] }),
18
20
  };
19
21
  static args = {};
20
22
  async run() {
@@ -26,6 +28,15 @@ export default class FaceCreate extends BaseCommand {
26
28
  const payload = { name: flags.name, alias: flags.alias };
27
29
  if (flags.description)
28
30
  payload.description = flags.description;
31
+ let addendum;
32
+ try {
33
+ addendum = resolveProfileAddendum(flags['profile-addendum'], flags['profile-addendum-file']);
34
+ }
35
+ catch (err) {
36
+ this.error(err instanceof Error ? err.message : String(err));
37
+ }
38
+ if (addendum !== undefined)
39
+ payload.profile_addendum = addendum;
29
40
  if (flags.formula) {
30
41
  payload.formula = flags.formula;
31
42
  if (flags['default-model'])
@@ -9,6 +9,9 @@ export default class FaceEdit extends BaseCommand {
9
9
  formula: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
10
10
  attr: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
11
11
  tool: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
12
+ 'profile-addendum': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
13
+ 'profile-addendum-file': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
14
+ 'clear-profile-addendum': import("@oclif/core/interfaces").BooleanFlag<boolean>;
12
15
  'base-url': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
13
16
  token: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
14
17
  'api-key': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
@@ -2,7 +2,7 @@ import { Args, Flags } from '@oclif/core';
2
2
  import { BaseCommand } from '../../base.js';
3
3
  import { FacesAPIError } from '../../client.js';
4
4
  import { CatalogService } from '../../catalog.js';
5
- import { renameFaceFields } from '../../utils.js';
5
+ import { renameFaceFields, resolveProfileAddendum } from '../../utils.js';
6
6
  export default class FaceEdit extends BaseCommand {
7
7
  static description = "Edit a face's metadata";
8
8
  static flags = {
@@ -14,6 +14,9 @@ export default class FaceEdit extends BaseCommand {
14
14
  formula: Flags.string({ description: 'New boolean formula (synthetic faces only)' }),
15
15
  attr: Flags.string({ description: 'Update attribute KEY=VALUE (repeatable)', multiple: true }),
16
16
  tool: Flags.string({ description: 'Tool names to set (replaces list, repeatable)', multiple: true }),
17
+ 'profile-addendum': Flags.string({ description: 'Replace the per-face system prompt (max 100,000 chars).' }),
18
+ 'profile-addendum-file': Flags.string({ description: 'Replace the per-face system prompt from a file.', exclusive: ['profile-addendum'] }),
19
+ 'clear-profile-addendum': Flags.boolean({ description: 'Remove the per-face system prompt.', exclusive: ['profile-addendum', 'profile-addendum-file'] }),
17
20
  };
18
21
  static args = {
19
22
  face_id: Args.string({ description: 'Face alias', required: true }),
@@ -42,6 +45,20 @@ export default class FaceEdit extends BaseCommand {
42
45
  payload.default_model = flags['default-model'];
43
46
  if (flags.description !== undefined)
44
47
  payload.description = flags.description;
48
+ if (flags['clear-profile-addendum']) {
49
+ payload.profile_addendum = '';
50
+ }
51
+ else {
52
+ let addendum;
53
+ try {
54
+ addendum = resolveProfileAddendum(flags['profile-addendum'], flags['profile-addendum-file']);
55
+ }
56
+ catch (err) {
57
+ this.error(err instanceof Error ? err.message : String(err));
58
+ }
59
+ if (addendum !== undefined)
60
+ payload.profile_addendum = addendum;
61
+ }
45
62
  const hasTags = flags.tag && flags.tag.length > 0;
46
63
  if (Object.keys(payload).length === 0 && !hasTags)
47
64
  this.error('Provide at least one field to update.');
@@ -3,6 +3,7 @@ export default class FaceGet extends BaseCommand {
3
3
  static description: string;
4
4
  static flags: {
5
5
  include: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
6
+ full: import("@oclif/core/interfaces").BooleanFlag<boolean>;
6
7
  'base-url': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
7
8
  token: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
8
9
  'api-key': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
@@ -7,6 +7,7 @@ export default class FaceGet extends BaseCommand {
7
7
  static flags = {
8
8
  ...BaseCommand.baseFlags,
9
9
  include: Flags.string({ description: 'Include extra fields: tags, teams (comma-separated)' }),
10
+ full: Flags.boolean({ description: 'Print the full profile_addendum instead of a truncated preview' }),
10
11
  };
11
12
  static args = {
12
13
  face_id: Args.string({ description: 'Face alias', required: true }),
@@ -55,6 +56,20 @@ export default class FaceGet extends BaseCommand {
55
56
  if (f.default_model)
56
57
  this.log(`default_model: ${f.default_model}`);
57
58
  }
59
+ if (f.profile_addendum) {
60
+ const text = f.profile_addendum;
61
+ if (flags.full) {
62
+ this.log(`profile_addendum (${text.length} chars):`);
63
+ this.log(text);
64
+ }
65
+ else {
66
+ const oneLine = text.replace(/\s+/g, ' ').trim();
67
+ const preview = oneLine.length > 160 ? `${oneLine.slice(0, 160)}…` : oneLine;
68
+ this.log(`profile_addendum (${text.length} chars): ${preview}`);
69
+ if (oneLine.length > 160)
70
+ this.log(' (use --full to print the whole prompt)');
71
+ }
72
+ }
58
73
  }
59
74
  return data;
60
75
  }
package/dist/utils.d.ts CHANGED
@@ -1,3 +1,11 @@
1
+ /** Max length of a face's profile_addendum (per-face system prompt). Mirrors the backend. */
2
+ export declare const PROFILE_ADDENDUM_MAX_CHARS = 100000;
3
+ /**
4
+ * Resolve a face's profile_addendum from the `--profile-addendum` / `--profile-addendum-file`
5
+ * flags. Returns undefined when neither is given (field left unchanged). Throws on a missing
6
+ * file or over-length content so the caller can surface a friendly error.
7
+ */
8
+ export declare function resolveProfileAddendum(text: string | undefined, file: string | undefined): string | undefined;
1
9
  /**
2
10
  * Flatten basic_facts/attributes from API's nested {value, status, identification} format
3
11
  * to simple {key: value} strings.
package/dist/utils.js CHANGED
@@ -1,3 +1,26 @@
1
+ import fs from 'node:fs';
2
+ /** Max length of a face's profile_addendum (per-face system prompt). Mirrors the backend. */
3
+ export const PROFILE_ADDENDUM_MAX_CHARS = 100_000;
4
+ /**
5
+ * Resolve a face's profile_addendum from the `--profile-addendum` / `--profile-addendum-file`
6
+ * flags. Returns undefined when neither is given (field left unchanged). Throws on a missing
7
+ * file or over-length content so the caller can surface a friendly error.
8
+ */
9
+ export function resolveProfileAddendum(text, file) {
10
+ let value;
11
+ if (file !== undefined) {
12
+ if (!fs.existsSync(file))
13
+ throw new Error(`File not found: ${file}`);
14
+ value = fs.readFileSync(file, 'utf8');
15
+ }
16
+ else if (text !== undefined) {
17
+ value = text;
18
+ }
19
+ if (value !== undefined && value.length > PROFILE_ADDENDUM_MAX_CHARS) {
20
+ throw new Error(`--profile-addendum is ${value.length} chars; max is ${PROFILE_ADDENDUM_MAX_CHARS}.`);
21
+ }
22
+ return value;
23
+ }
1
24
  /**
2
25
  * Flatten basic_facts/attributes from API's nested {value, status, identification} format
3
26
  * to simple {key: value} strings.