@adaptiqai/deepseek-harness 0.2.12 → 0.2.14

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.
@@ -30,7 +30,7 @@ export declare function MemoryCallout({ store, t }: {
30
30
  * memory, thinking levels, region. A field is left out only when unknown.
31
31
  */
32
32
  export declare function modelFacts(model: ModelView, t: T): string;
33
- /** One model row: name, facts, lanes, status. */
33
+ /** One model row: name, facts, status. */
34
34
  export declare function ModelRow({ model, t }: {
35
35
  model: ModelView;
36
36
  t: T;
@@ -9,7 +9,7 @@ export declare const COUNT_UP_MS = 900;
9
9
  * The pill's words while a request waits.
10
10
  * @param t - translate.
11
11
  * @param kind - what the request waits for.
12
- * @returns e.g. "Waiting for a free lane".
12
+ * @returns e.g. "Waiting in line".
13
13
  */
14
14
  export declare function waitText(t: T, kind: WaitKind): string;
15
15
  /**
@@ -7,6 +7,7 @@
7
7
  import { LlmAdapter, LlmError } from '@deepseek-ai/dsh-llm';
8
8
  import type { GenerateOptions, LlmModelInfo, LlmProviderInfo, LlmResolvedModelInfo, PreparedAdapterCall, ResolvedRetryPolicy, StreamChunk } from '@deepseek-ai/dsh-llm';
9
9
  import { type AdaptiqFailure, type AuthManager, type CatalogModel, type RequestEvents, type UserTurn } from '@adaptiqai/core';
10
+ import { type ImageLimits, type ImageRef, type ImageSource } from './images.ts';
10
11
  import { type ParentSession, type ReferencedSession } from './wire.ts';
11
12
  /** What the adapter tells the rest of the plugin about each request. */
12
13
  export interface AdapterDeps {
@@ -42,6 +43,14 @@ export interface AdapterDeps {
42
43
  readonly events: RequestEvents;
43
44
  /** Whether the server behind a model puts idle conversations to sleep (it reports session history apart). */
44
45
  readonly autoSleep?: (model: string) => boolean;
46
+ /** The harness's attachment service, where attached images are stored (absent on hosts without one). */
47
+ attachments?(): ImageSource | undefined;
48
+ /** Where the model's tools can read the stored copy of an image. */
49
+ imageAccess?(ref: ImageRef): {
50
+ readonlyPath: string;
51
+ } | undefined;
52
+ /** The engine's image limits (tests use smaller ones). */
53
+ readonly imageLimits?: ImageLimits;
45
54
  /** Diagnostics for one request (no content), when a debug log is on. */
46
55
  debug?(message: string): void;
47
56
  readonly fetch?: typeof fetch;
@@ -78,5 +87,11 @@ export declare class AdaptiqAdapter extends LlmAdapter {
78
87
  resolveModel(provider: string, model: string, signal?: AbortSignal): Promise<LlmResolvedModelInfo>;
79
88
  prepareCall(provider: string, model: string, signal?: AbortSignal): Promise<PreparedAdapterCall>;
80
89
  stream(options: GenerateOptions): AsyncIterable<StreamChunk>;
90
+ /**
91
+ * The request's images, read from the harness's stored copies, when the
92
+ * model's card says it reads images. Otherwise each image goes as a short
93
+ * note and the person is told.
94
+ */
95
+ private images;
81
96
  private generate;
82
97
  }
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Images a person attached, as inline data the AdaptiqAI API accepts.
3
+ *
4
+ * The harness stores each attached image once, content-addressed (sha256), and
5
+ * hands the adapter a durable reference. The bytes sent are read from that
6
+ * stored copy, never from the file the person picked, so a history image is the
7
+ * same bytes on every turn (the engine dedupes by content hash) even when the
8
+ * original file has changed since.
9
+ */
10
+ import type { ImageBlock, RequestMessage } from '@deepseek-ai/dsh-llm';
11
+ /** One image reference as the harness stores it. */
12
+ export type ImageRef = ImageBlock['attachment'];
13
+ /** Image media types the engine accepts. */
14
+ export type ImageMediaType = 'image/png' | 'image/jpeg' | 'image/webp' | 'image/gif';
15
+ /** What the engine accepts per request. */
16
+ export interface ImageLimits {
17
+ /** Image parts in one request (history included). */
18
+ readonly maxImages: number;
19
+ /** Encoded bytes of one image. */
20
+ readonly maxImageBytes: number;
21
+ /** Width × height of one image; larger ones are scaled down before sending. */
22
+ readonly maxPixels: number;
23
+ }
24
+ /** The engine's limits behind api.adaptiqai.com (8 images, 20 MiB and 16.8 MP each); pixels kept a little under. */
25
+ export declare const ENGINE_IMAGE_LIMITS: ImageLimits;
26
+ /** The request version the harness's attachment service makes of one stored image. */
27
+ export interface RequestImageVersion {
28
+ readonly data: Uint8Array;
29
+ readonly mediaType: string;
30
+ readonly width: number;
31
+ readonly height: number;
32
+ }
33
+ /** The part of the harness's attachment service (`ctx.attachments`) the adapter reads images through. */
34
+ export interface ImageSource {
35
+ readImageRequest(ref: ImageRef, target: {
36
+ width: number;
37
+ height: number;
38
+ maxBytes: number;
39
+ }, signal?: AbortSignal): Promise<RequestImageVersion>;
40
+ }
41
+ /** One image ready for the wire. */
42
+ export interface WireImage {
43
+ /** `data:<mime>;base64,...` */
44
+ readonly url: string;
45
+ readonly width: number;
46
+ readonly height: number;
47
+ }
48
+ /** An image the engine would refuse, said in plain words. */
49
+ export declare class ImageProblem extends Error {
50
+ readonly name = "ImageProblem";
51
+ }
52
+ /**
53
+ * The image format, read from the bytes themselves.
54
+ * @param data - encoded image bytes.
55
+ * @returns the media type, or null when the bytes are no PNG, JPEG, WebP or GIF.
56
+ */
57
+ export declare function sniffImageType(data: Uint8Array): ImageMediaType | null;
58
+ /**
59
+ * The size to send one image at: its own, or scaled down (aspect kept) to fit the pixel limit.
60
+ * @param width - stored width.
61
+ * @param height - stored height.
62
+ * @param maxPixels - width × height limit.
63
+ * @returns target width and height.
64
+ */
65
+ export declare function fitPixels(width: number, height: number, maxPixels: number): {
66
+ width: number;
67
+ height: number;
68
+ };
69
+ /**
70
+ * The images a request sends (not offloaded by the harness), one entry per occurrence, oldest first.
71
+ * @param messages - the request history.
72
+ * @returns image blocks in request order.
73
+ */
74
+ export declare function sentImages(messages: readonly RequestMessage[]): ImageBlock[];
75
+ /**
76
+ * Whether any message of the request carries an image.
77
+ * @param messages - the request history.
78
+ * @returns true when one does.
79
+ */
80
+ export declare function hasImages(messages: readonly RequestMessage[]): boolean;
81
+ /**
82
+ * Read every image the request sends from the harness's stored copies, check
83
+ * it against the engine's limits and encode it as a data URL.
84
+ * @param messages - the request history.
85
+ * @param source - the harness's attachment service.
86
+ * @param limits - the engine's limits.
87
+ * @param signal - cancellation.
88
+ * @returns attachment id → wire image.
89
+ * @throws ImageProblem when an image is not one the engine accepts.
90
+ */
91
+ export declare function prepareImages(messages: readonly RequestMessage[], source: ImageSource, limits: ImageLimits, signal?: AbortSignal): Promise<Map<string, WireImage>>;
@@ -1,17 +1,13 @@
1
- /**
2
- * Harness request → OpenAI Chat Completions body. Model-specific behaviour
3
- * (thinking field and values, sampling defaults) comes only from the
4
- * model's catalog entry.
5
- */
6
1
  import type { GenerateOptions, RequestMessage } from '@deepseek-ai/dsh-llm';
7
2
  import { type CatalogModel, type SessionRole, type UserTurn } from '@adaptiqai/core';
3
+ import type { ImageRef, WireImage } from './images.ts';
8
4
  /** One Chat Completions message. */
9
5
  export type WireMessage = {
10
6
  role: 'system';
11
7
  content: string;
12
8
  } | {
13
9
  role: 'user';
14
- content: string;
10
+ content: string | WirePart[];
15
11
  } | {
16
12
  role: 'assistant';
17
13
  content: string | null;
@@ -22,6 +18,25 @@ export type WireMessage = {
22
18
  tool_call_id: string;
23
19
  content: string;
24
20
  };
21
+ /** One part of a user message that carries images, in the person's order. */
22
+ export type WirePart = {
23
+ type: 'text';
24
+ text: string;
25
+ } | {
26
+ type: 'image_url';
27
+ image_url: {
28
+ url: string;
29
+ };
30
+ };
31
+ /** How the images of a request go on the wire. */
32
+ export interface WireImages {
33
+ /** Attachment id → inline image; null when the model reads text only (each image becomes a short note). */
34
+ readonly sent: ReadonlyMap<string, WireImage> | null;
35
+ /** Where the model's tools can read the harness's stored copy of an image. */
36
+ readonly access?: (ref: ImageRef) => {
37
+ readonlyPath: string;
38
+ } | undefined;
39
+ }
25
40
  export interface WireToolCall {
26
41
  id: string;
27
42
  type: 'function';
@@ -40,6 +55,8 @@ export interface WireExtras {
40
55
  readonly includeUsage?: boolean;
41
56
  /** Referenced sessions attached to this conversation and ready, by session id → name. */
42
57
  readonly recalled?: ReadonlyMap<string, string>;
58
+ /** The request's images; without it every image becomes a short note. */
59
+ readonly images?: WireImages;
43
60
  }
44
61
  /** One session another message mentioned with `@`, as the harness snapshot records it. */
45
62
  export interface ReferencedSession {
@@ -94,9 +111,10 @@ export declare function userTurns(messages: readonly RequestMessage[]): UserTurn
94
111
  * Convert the harness history to Chat Completions messages.
95
112
  * @param options - the harness request.
96
113
  * @param recalled - referenced sessions read from memory: their snapshots become one line.
114
+ * @param images - the request's images; without it each image becomes a short note.
97
115
  * @returns the wire messages in order.
98
116
  */
99
- export declare function wireMessages(options: Pick<GenerateOptions, 'messages' | 'system'>, recalled?: ReadonlyMap<string, string>): WireMessage[];
117
+ export declare function wireMessages(options: Pick<GenerateOptions, 'messages' | 'system'>, recalled?: ReadonlyMap<string, string>, images?: WireImages): WireMessage[];
100
118
  /**
101
119
  * Build the request body for one call.
102
120
  * @param options - the harness request.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adaptiqai/deepseek-harness",
3
- "version": "0.2.12",
3
+ "version": "0.2.14",
4
4
  "description": "AdaptiqAI for DeepSeek Harness: models with 5M-token native memory and Knowledge. Sign up, get a model and work without leaving the harness",
5
5
  "keywords": [
6
6
  "dsh-plugin",
@@ -90,14 +90,7 @@
90
90
  "react-dom": "~18.3.1",
91
91
  "typescript": "~5.9.3",
92
92
  "vitest": "~3.2.7",
93
- "@adaptiqai/core": "workspace:*"
94
- },
95
- "scripts": {
96
- "link-dsh": "node scripts/link-dsh.mjs",
97
- "build": "node scripts/gen-typert.mjs && node scripts/build.mjs",
98
- "typecheck": "tsc -p tsconfig.json --noEmit",
99
- "test": "vitest run",
100
- "pack:local": "npm run build && pnpm pack --pack-destination ../../dist"
93
+ "@adaptiqai/core": "0.2.10"
101
94
  },
102
95
  "repository": {
103
96
  "type": "git",
@@ -106,5 +99,12 @@
106
99
  },
107
100
  "publishConfig": {
108
101
  "access": "public"
102
+ },
103
+ "scripts": {
104
+ "link-dsh": "node scripts/link-dsh.mjs",
105
+ "build": "node scripts/gen-typert.mjs && node scripts/build.mjs",
106
+ "typecheck": "tsc -p tsconfig.json --noEmit",
107
+ "test": "vitest run",
108
+ "pack:local": "npm run build && pnpm pack --pack-destination ../../dist"
109
109
  }
110
- }
110
+ }