@gobing-ai/ts-ai-runner 0.5.1 → 0.5.2

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.
@@ -356,14 +356,14 @@ const AGENT_SESSION_CAPABILITY = {
356
356
  supportsSessionDir: true,
357
357
  supportsPersistentStdin: true,
358
358
  supportsStructuredOutput: true,
359
- verifiedAgainst: '0.85.1',
359
+ verifiedAgainst: '0.87.0',
360
360
  },
361
361
  claude: {
362
362
  supportsResumeById: true,
363
363
  supportsSessionDir: false,
364
364
  supportsPersistentStdin: true,
365
365
  supportsStructuredOutput: true,
366
- verifiedAgainst: '2.1.274',
366
+ verifiedAgainst: '2.1.278',
367
367
  // Persistent stdin is shim-wired: `-p --input-format stream-json --output-format
368
368
  // stream-json` keeps the process alive reading JSONL envelopes (verified --help;
369
369
  // --input-format only works with --print).
@@ -374,7 +374,7 @@ const AGENT_SESSION_CAPABILITY = {
374
374
  supportsSessionDir: false,
375
375
  supportsPersistentStdin: false,
376
376
  supportsStructuredOutput: true,
377
- verifiedAgainst: '0.154.0',
377
+ verifiedAgainst: '0.155.1',
378
378
  // R3 branch 2: `exec resume <id> <prompt>` is the working non-interactive
379
379
  // resume (verified 0.154.0) — wired in getPromptCommand below.
380
380
  note: 'no session-dir flag — sessionDir is ignored; `exec` carries one prompt arg (stdin `-` is one-shot), so no multi-turn stdin',
@@ -394,7 +394,7 @@ const AGENT_SESSION_CAPABILITY = {
394
394
  supportsSessionDir: false,
395
395
  supportsPersistentStdin: false,
396
396
  supportsStructuredOutput: true,
397
- verifiedAgainst: '1.0.34',
397
+ verifiedAgainst: '1.0.40',
398
398
  note: 'no session-dir flag — sessionDir is ignored (best-effort isolate); no multi-turn stdin input mode',
399
399
  },
400
400
  gemini: {
@@ -19,10 +19,14 @@ export interface DecisionMaker {
19
19
  no?: Desc;
20
20
  }): Promise<NoulAnswer>;
21
21
  }
22
+ /** Available named decision backends (task 0080). */
23
+ export type DecisionBackend = 'typesafe' | 'laya-local';
22
24
  /** Factory options: driver selection, credential injection, and transport tuning. */
23
25
  export interface DecisionMakerOptions {
24
- /** Custom driver — when supplied, the default TypeSafe driver is never constructed and no key is required. */
26
+ /** Custom driver — when supplied, `backend` is ignored, no default driver is constructed and no key is required. */
25
27
  driver?: DecisionDriver;
28
+ /** Named backend selector. Default: `'typesafe'`. Resolution order: `driver` → `backend` → `'typesafe'`. */
29
+ backend?: DecisionBackend;
26
30
  /** Injected env record; defaults to `getProcessEnv()` (doctor-runner convention). */
27
31
  env?: Record<string, string | undefined>;
28
32
  /** Explicit key — wins over `env.TYPESAFE_API_KEY`. */
@@ -34,12 +38,11 @@ export interface DecisionMakerOptions {
34
38
  maxRetries?: number;
35
39
  /** Injected fetch for tests. */
36
40
  fetch?: typeof fetch;
41
+ [key: string]: unknown;
37
42
  }
38
43
  /**
39
- * Build a DecisionMaker. `options.driver` wins when supplied; otherwise the
40
- * TypeSafe driver is constructed lazily on first use, after key resolution —
41
- * so a custom driver never requires a key and a missing key fails before any
42
- * request (R6/R7).
44
+ * Build a DecisionMaker. `options.driver` wins when supplied; otherwise `options.backend`
45
+ * resolves the driver (default `'typesafe'`). The driver is constructed lazily on first use.
43
46
  */
44
47
  export declare function createDecisionMaker(options?: DecisionMakerOptions): DecisionMaker;
45
48
  //# sourceMappingURL=decision-maker.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"decision-maker.d.ts","sourceRoot":"","sources":["../../src/decision/decision-maker.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EACR,UAAU,EACV,YAAY,EACZ,cAAc,EACd,aAAa,EACb,IAAI,EACJ,UAAU,EACV,QAAQ,EACR,WAAW,EACd,MAAM,SAAS,CAAC;AAKjB,yFAAyF;AACzF,MAAM,WAAW,aAAa;IAC1B,iFAAiF;IACjF,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,sFAAsF;IACtF,GAAG,CAAC,KAAK,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,GAAG,EAAE;QAC/C,KAAK,EAAE,aAAa,CAAC;QACrB,SAAS,EAAE,CAAC,CAAC;QACb,KAAK,CAAC,EAAE,MAAM,CAAC;KAClB,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3B,yEAAyE;IACzE,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,MAAM,EACzB,KAAK,EAAE,aAAa,EACpB,MAAM,EAAE,IAAI,EACZ,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,GACxB,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5B,gFAAgF;IAChF,KAAK,CAAC,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAC1G,wEAAwE;IACxE,IAAI,CAAC,KAAK,EAAE,aAAa,EAAE,MAAM,CAAC,EAAE,IAAI,EAAE,QAAQ,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,IAAI,CAAC;QAAC,EAAE,CAAC,EAAE,IAAI,CAAA;KAAE,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;CACxG;AAED,qFAAqF;AACrF,MAAM,WAAW,oBAAoB;IACjC,8GAA8G;IAC9G,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,qFAAqF;IACrF,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACzC,uDAAuD;IACvD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4EAA4E;IAC5E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gCAAgC;IAChC,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACxB;AAkBD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,oBAAyB,GAAG,aAAa,CA6CrF"}
1
+ {"version":3,"file":"decision-maker.d.ts","sourceRoot":"","sources":["../../src/decision/decision-maker.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EACR,UAAU,EACV,YAAY,EACZ,cAAc,EACd,aAAa,EACb,IAAI,EACJ,UAAU,EACV,QAAQ,EACR,WAAW,EACd,MAAM,SAAS,CAAC;AAKjB,yFAAyF;AACzF,MAAM,WAAW,aAAa;IAC1B,iFAAiF;IACjF,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,sFAAsF;IACtF,GAAG,CAAC,KAAK,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,GAAG,EAAE;QAC/C,KAAK,EAAE,aAAa,CAAC;QACrB,SAAS,EAAE,CAAC,CAAC;QACb,KAAK,CAAC,EAAE,MAAM,CAAC;KAClB,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3B,yEAAyE;IACzE,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,MAAM,EACzB,KAAK,EAAE,aAAa,EACpB,MAAM,EAAE,IAAI,EACZ,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,GACxB,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5B,gFAAgF;IAChF,KAAK,CAAC,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAC1G,wEAAwE;IACxE,IAAI,CAAC,KAAK,EAAE,aAAa,EAAE,MAAM,CAAC,EAAE,IAAI,EAAE,QAAQ,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,IAAI,CAAC;QAAC,EAAE,CAAC,EAAE,IAAI,CAAA;KAAE,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;CACxG;AAED,qDAAqD;AACrD,MAAM,MAAM,eAAe,GAAG,UAAU,GAAG,YAAY,CAAC;AAExD,qFAAqF;AACrF,MAAM,WAAW,oBAAoB;IACjC,oHAAoH;IACpH,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB,4GAA4G;IAC5G,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,qFAAqF;IACrF,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACzC,uDAAuD;IACvD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4EAA4E;IAC5E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gCAAgC;IAChC,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IACrB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CAC1B;AAsCD;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,oBAAyB,GAAG,aAAa,CAoDrF"}
@@ -21,33 +21,52 @@ function resolveApiKey(options) {
21
21
  }
22
22
  return apiKey;
23
23
  }
24
+ const LAYA_DRIVER_PACKAGE = '@gobing-ai/ts-laya-mlx';
25
+ async function resolveLayaDriver(options) {
26
+ try {
27
+ const mod = (await import(LAYA_DRIVER_PACKAGE));
28
+ if (typeof mod.createLayaDriver !== 'function') {
29
+ throw new Error(`Module '${LAYA_DRIVER_PACKAGE}' does not export createLayaDriver`);
30
+ }
31
+ return mod.createLayaDriver(options);
32
+ }
33
+ catch (cause) {
34
+ throw new DecisionConfigError(`The 'laya-local' backend requires '${LAYA_DRIVER_PACKAGE}' to be installed; install it with 'bun add ${LAYA_DRIVER_PACKAGE}'`, 'LAYA_BACKEND', { cause });
35
+ }
36
+ }
24
37
  /**
25
- * Build a DecisionMaker. `options.driver` wins when supplied; otherwise the
26
- * TypeSafe driver is constructed lazily on first use, after key resolution —
27
- * so a custom driver never requires a key and a missing key fails before any
28
- * request (R6/R7).
38
+ * Build a DecisionMaker. `options.driver` wins when supplied; otherwise `options.backend`
39
+ * resolves the driver (default `'typesafe'`). The driver is constructed lazily on first use.
29
40
  */
30
41
  export function createDecisionMaker(options = {}) {
31
- // Lazy driver slot: resolved on first use, at most once. A caller-supplied
32
- // driver never reaches key resolution or default-driver construction (R6).
33
- let defaultDriver;
34
- const resolveDriver = () => {
42
+ let resolvedDriver;
43
+ const getDriver = async () => {
35
44
  if (options.driver)
36
45
  return options.driver;
37
- defaultDriver ??= createTypesafeDriver({
38
- apiKey: resolveApiKey(options),
39
- model: options.model,
40
- baseURL: options.baseURL,
41
- timeoutMs: options.timeoutMs,
42
- maxRetries: options.maxRetries,
43
- fetch: options.fetch,
44
- });
45
- return defaultDriver;
46
+ if (resolvedDriver)
47
+ return resolvedDriver;
48
+ const backend = options.backend ?? 'typesafe';
49
+ if (backend === 'typesafe') {
50
+ resolvedDriver = createTypesafeDriver({
51
+ apiKey: resolveApiKey(options),
52
+ model: options.model,
53
+ baseURL: options.baseURL,
54
+ timeoutMs: options.timeoutMs,
55
+ maxRetries: options.maxRetries,
56
+ fetch: options.fetch,
57
+ });
58
+ return resolvedDriver;
59
+ }
60
+ if (backend === 'laya-local') {
61
+ resolvedDriver = await resolveLayaDriver(options);
62
+ return resolvedDriver;
63
+ }
64
+ throw new DecisionConfigError(`Unknown decision backend '${backend}'`, 'backend');
46
65
  };
47
66
  const ask = async (req) => {
48
67
  // R3: the questions map reaches the driver untouched — same reference,
49
68
  // no reordering, renaming, or dropping.
50
- const driver = resolveDriver();
69
+ const driver = await getDriver();
51
70
  validateQuestions(req.questions);
52
71
  const answers = await driver.ask(req);
53
72
  validateAnswers(req.questions, answers);
@@ -55,7 +74,7 @@ export function createDecisionMaker(options = {}) {
55
74
  return answers;
56
75
  };
57
76
  return {
58
- driver: options.driver?.name ?? 'typesafe',
77
+ driver: options.driver?.name ?? options.backend ?? 'typesafe',
59
78
  ask,
60
79
  // R4/R5: each sugar method is one `ask` with exactly one `q.*` question,
61
80
  // unwrapping the single answer — no second driver call, no duplicated
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gobing-ai/ts-ai-runner",
3
- "version": "0.5.1",
3
+ "version": "0.5.2",
4
4
  "description": "@gobing-ai/ts-ai-runner — Coding-agent shims, detection, doctor checks, and prompt execution.",
5
5
  "keywords": [
6
6
  "typescript",
@@ -47,13 +47,13 @@
47
47
  "release": "echo 'Manual publish is disabled. Releases go through GitHub Actions via Trusted Publishing — push a tag: git tag @gobing-ai/ts-ai-runner-v<version> && git push --tags' && exit 1"
48
48
  },
49
49
  "dependencies": {
50
- "@gobing-ai/ts-infra": "^0.5.1",
51
- "@gobing-ai/ts-runtime": "^0.5.1",
50
+ "@gobing-ai/ts-infra": "^0.5.2",
51
+ "@gobing-ai/ts-runtime": "^0.5.2",
52
52
  "@typesafe-ai/sdk": "0.6.0"
53
53
  },
54
54
  "devDependencies": {
55
55
  "@types/bun": "1.3.14",
56
- "@gobing-ai/ts-db": "^0.5.1"
56
+ "@gobing-ai/ts-db": "^0.5.2"
57
57
  },
58
58
  "publishConfig": {
59
59
  "access": "public"
@@ -477,14 +477,14 @@ const AGENT_SESSION_CAPABILITY: Readonly<Record<AgentName, AgentSessionCapabilit
477
477
  supportsSessionDir: true,
478
478
  supportsPersistentStdin: true,
479
479
  supportsStructuredOutput: true,
480
- verifiedAgainst: '0.85.1',
480
+ verifiedAgainst: '0.87.0',
481
481
  },
482
482
  claude: {
483
483
  supportsResumeById: true,
484
484
  supportsSessionDir: false,
485
485
  supportsPersistentStdin: true,
486
486
  supportsStructuredOutput: true,
487
- verifiedAgainst: '2.1.274',
487
+ verifiedAgainst: '2.1.278',
488
488
  // Persistent stdin is shim-wired: `-p --input-format stream-json --output-format
489
489
  // stream-json` keeps the process alive reading JSONL envelopes (verified --help;
490
490
  // --input-format only works with --print).
@@ -495,7 +495,7 @@ const AGENT_SESSION_CAPABILITY: Readonly<Record<AgentName, AgentSessionCapabilit
495
495
  supportsSessionDir: false,
496
496
  supportsPersistentStdin: false,
497
497
  supportsStructuredOutput: true,
498
- verifiedAgainst: '0.154.0',
498
+ verifiedAgainst: '0.155.1',
499
499
  // R3 branch 2: `exec resume <id> <prompt>` is the working non-interactive
500
500
  // resume (verified 0.154.0) — wired in getPromptCommand below.
501
501
  note: 'no session-dir flag — sessionDir is ignored; `exec` carries one prompt arg (stdin `-` is one-shot), so no multi-turn stdin',
@@ -515,7 +515,7 @@ const AGENT_SESSION_CAPABILITY: Readonly<Record<AgentName, AgentSessionCapabilit
515
515
  supportsSessionDir: false,
516
516
  supportsPersistentStdin: false,
517
517
  supportsStructuredOutput: true,
518
- verifiedAgainst: '1.0.34',
518
+ verifiedAgainst: '1.0.40',
519
519
  note: 'no session-dir flag — sessionDir is ignored (best-effort isolate); no multi-turn stdin input mode',
520
520
  },
521
521
  gemini: {
@@ -42,10 +42,15 @@ export interface DecisionMaker {
42
42
  noul(state: DecisionState, prompt?: Desc, outcomes?: { yes?: Desc; no?: Desc }): Promise<NoulAnswer>;
43
43
  }
44
44
 
45
+ /** Available named decision backends (task 0080). */
46
+ export type DecisionBackend = 'typesafe' | 'laya-local';
47
+
45
48
  /** Factory options: driver selection, credential injection, and transport tuning. */
46
49
  export interface DecisionMakerOptions {
47
- /** Custom driver — when supplied, the default TypeSafe driver is never constructed and no key is required. */
50
+ /** Custom driver — when supplied, `backend` is ignored, no default driver is constructed and no key is required. */
48
51
  driver?: DecisionDriver;
52
+ /** Named backend selector. Default: `'typesafe'`. Resolution order: `driver` → `backend` → `'typesafe'`. */
53
+ backend?: DecisionBackend;
49
54
  /** Injected env record; defaults to `getProcessEnv()` (doctor-runner convention). */
50
55
  env?: Record<string, string | undefined>;
51
56
  /** Explicit key — wins over `env.TYPESAFE_API_KEY`. */
@@ -57,6 +62,7 @@ export interface DecisionMakerOptions {
57
62
  maxRetries?: number;
58
63
  /** Injected fetch for tests. */
59
64
  fetch?: typeof fetch;
65
+ [key: string]: unknown;
60
66
  }
61
67
 
62
68
  /**
@@ -75,27 +81,52 @@ function resolveApiKey(options: DecisionMakerOptions): string {
75
81
  return apiKey;
76
82
  }
77
83
 
84
+ const LAYA_DRIVER_PACKAGE = '@gobing-ai/ts-laya-mlx';
85
+
86
+ async function resolveLayaDriver(options: DecisionMakerOptions): Promise<DecisionDriver> {
87
+ try {
88
+ const mod = (await import(LAYA_DRIVER_PACKAGE)) as {
89
+ createLayaDriver?: (opts?: unknown) => DecisionDriver;
90
+ };
91
+ if (typeof mod.createLayaDriver !== 'function') {
92
+ throw new Error(`Module '${LAYA_DRIVER_PACKAGE}' does not export createLayaDriver`);
93
+ }
94
+ return mod.createLayaDriver(options);
95
+ } catch (cause) {
96
+ throw new DecisionConfigError(
97
+ `The 'laya-local' backend requires '${LAYA_DRIVER_PACKAGE}' to be installed; install it with 'bun add ${LAYA_DRIVER_PACKAGE}'`,
98
+ 'LAYA_BACKEND',
99
+ { cause },
100
+ );
101
+ }
102
+ }
103
+
78
104
  /**
79
- * Build a DecisionMaker. `options.driver` wins when supplied; otherwise the
80
- * TypeSafe driver is constructed lazily on first use, after key resolution —
81
- * so a custom driver never requires a key and a missing key fails before any
82
- * request (R6/R7).
105
+ * Build a DecisionMaker. `options.driver` wins when supplied; otherwise `options.backend`
106
+ * resolves the driver (default `'typesafe'`). The driver is constructed lazily on first use.
83
107
  */
84
108
  export function createDecisionMaker(options: DecisionMakerOptions = {}): DecisionMaker {
85
- // Lazy driver slot: resolved on first use, at most once. A caller-supplied
86
- // driver never reaches key resolution or default-driver construction (R6).
87
- let defaultDriver: DecisionDriver | undefined;
88
- const resolveDriver = (): DecisionDriver => {
109
+ let resolvedDriver: DecisionDriver | undefined;
110
+ const getDriver = async (): Promise<DecisionDriver> => {
89
111
  if (options.driver) return options.driver;
90
- defaultDriver ??= createTypesafeDriver({
91
- apiKey: resolveApiKey(options),
92
- model: options.model,
93
- baseURL: options.baseURL,
94
- timeoutMs: options.timeoutMs,
95
- maxRetries: options.maxRetries,
96
- fetch: options.fetch,
97
- });
98
- return defaultDriver;
112
+ if (resolvedDriver) return resolvedDriver;
113
+ const backend = options.backend ?? 'typesafe';
114
+ if (backend === 'typesafe') {
115
+ resolvedDriver = createTypesafeDriver({
116
+ apiKey: resolveApiKey(options),
117
+ model: options.model,
118
+ baseURL: options.baseURL,
119
+ timeoutMs: options.timeoutMs,
120
+ maxRetries: options.maxRetries,
121
+ fetch: options.fetch,
122
+ });
123
+ return resolvedDriver;
124
+ }
125
+ if (backend === 'laya-local') {
126
+ resolvedDriver = await resolveLayaDriver(options);
127
+ return resolvedDriver;
128
+ }
129
+ throw new DecisionConfigError(`Unknown decision backend '${backend}'`, 'backend');
99
130
  };
100
131
 
101
132
  const ask = async <const Q extends Record<string, Question>>(req: {
@@ -105,7 +136,7 @@ export function createDecisionMaker(options: DecisionMakerOptions = {}): Decisio
105
136
  }): Promise<AnswersFor<Q>> => {
106
137
  // R3: the questions map reaches the driver untouched — same reference,
107
138
  // no reordering, renaming, or dropping.
108
- const driver = resolveDriver();
139
+ const driver = await getDriver();
109
140
  validateQuestions(req.questions);
110
141
  const answers = await driver.ask(req);
111
142
  validateAnswers(req.questions, answers);
@@ -114,7 +145,7 @@ export function createDecisionMaker(options: DecisionMakerOptions = {}): Decisio
114
145
  };
115
146
 
116
147
  return {
117
- driver: options.driver?.name ?? 'typesafe',
148
+ driver: options.driver?.name ?? options.backend ?? 'typesafe',
118
149
  ask,
119
150
  // R4/R5: each sugar method is one `ask` with exactly one `q.*` question,
120
151
  // unwrapping the single answer — no second driver call, no duplicated